79 lines
1.6 KiB
Go
79 lines
1.6 KiB
Go
package email
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
const defaultSendTimeout = 10 * time.Second
|
|
|
|
// Chain tries senders in ascending Sort order until one succeeds.
|
|
type Chain struct {
|
|
senders []Sender
|
|
timeout time.Duration
|
|
}
|
|
|
|
type ChainOption func(*Chain)
|
|
|
|
func WithTimeout(d time.Duration) ChainOption {
|
|
return func(c *Chain) {
|
|
c.timeout = d
|
|
}
|
|
}
|
|
|
|
func NewChain(senders ...Sender) *Chain {
|
|
c := &Chain{
|
|
senders: append([]Sender(nil), senders...),
|
|
timeout: defaultSendTimeout,
|
|
}
|
|
c.sortSenders()
|
|
return c
|
|
}
|
|
|
|
func NewChainWithOptions(senders []Sender, opts ...ChainOption) *Chain {
|
|
c := &Chain{
|
|
senders: append([]Sender(nil), senders...),
|
|
timeout: defaultSendTimeout,
|
|
}
|
|
for _, opt := range opts {
|
|
opt(c)
|
|
}
|
|
c.sortSenders()
|
|
return c
|
|
}
|
|
|
|
func (c *Chain) sortSenders() {
|
|
sort.Slice(c.senders, func(i, j int) bool {
|
|
return c.senders[i].Sort() < c.senders[j].Sort()
|
|
})
|
|
}
|
|
|
|
// Send returns the winning provider name and provider-assigned message id.
|
|
func (c *Chain) Send(ctx context.Context, msg *Message) (providerName, messageID string, err error) {
|
|
if len(c.senders) == 0 {
|
|
return "", "", fmt.Errorf("email: no senders configured")
|
|
}
|
|
if msg == nil {
|
|
return "", "", fmt.Errorf("email: message is nil")
|
|
}
|
|
|
|
sendCtx, cancel := context.WithTimeout(ctx, c.timeout)
|
|
defer cancel()
|
|
|
|
var lastErr error
|
|
for _, sender := range c.senders {
|
|
id, sendErr := sender.Send(sendCtx, msg)
|
|
if sendErr == nil {
|
|
return sender.Name(), id, nil
|
|
}
|
|
lastErr = sendErr
|
|
}
|
|
|
|
if lastErr == nil {
|
|
lastErr = fmt.Errorf("email: all providers failed")
|
|
}
|
|
return "", "", fmt.Errorf("email: all providers failed: %w", lastErr)
|
|
}
|