68 lines
1.4 KiB
Go
68 lines
1.4 KiB
Go
package imapx
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/emersion/go-imap/v2/imapclient"
|
|
)
|
|
|
|
type Endpoint struct {
|
|
Host string
|
|
Port int
|
|
TLSMode string // ssl | starttls | plain
|
|
}
|
|
|
|
func (e Endpoint) addr() string { return fmt.Sprintf("%s:%d", e.Host, e.Port) }
|
|
|
|
func dialOnce(ep Endpoint) (*imapclient.Client, error) {
|
|
switch ep.TLSMode {
|
|
case "ssl":
|
|
return imapclient.DialTLS(ep.addr(), &imapclient.Options{
|
|
TLSConfig: &tls.Config{ServerName: ep.Host},
|
|
})
|
|
case "starttls":
|
|
return imapclient.DialStartTLS(ep.addr(), &imapclient.Options{
|
|
TLSConfig: &tls.Config{ServerName: ep.Host},
|
|
})
|
|
case "plain":
|
|
return imapclient.DialInsecure(ep.addr(), nil)
|
|
default:
|
|
return nil, fmt.Errorf("unknown tls_mode %q", ep.TLSMode)
|
|
}
|
|
}
|
|
|
|
func Connect(ctx context.Context, ep Endpoint) (*imapclient.Client, error) {
|
|
const attempts = 3
|
|
var lastErr error
|
|
for i := 0; i < attempts; i++ {
|
|
if err := ctx.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
c, err := dialOnce(ep)
|
|
if err == nil {
|
|
return c, nil
|
|
}
|
|
lastErr = err
|
|
if i < attempts-1 {
|
|
backoff := time.Duration(200*(i+1)) * time.Millisecond
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil, ctx.Err()
|
|
case <-time.After(backoff):
|
|
}
|
|
}
|
|
}
|
|
return nil, lastErr
|
|
}
|
|
|
|
func TestEndpoint(ctx context.Context, ep Endpoint) error {
|
|
c, err := Connect(ctx, ep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.Logout().Wait()
|
|
}
|