1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
package send
import (
"bufio"
"bytes"
"fmt"
"io"
"net/url"
"github.com/emersion/go-message/mail"
"git.sr.ht/~rjarry/aerc/worker/types"
)
// NewSender returns an io.WriterCloser into which the caller can write
// contents of a message. The caller must invoke the Close() method on the
// sender when finished.
func NewSender(
worker *types.Worker, uri *url.URL, domain string,
from *mail.Address, rcpts []*mail.Address,
copyTo []string, requestDSN bool,
) (io.WriteCloser, error) {
protocol, auth, err := parseScheme(uri)
if err != nil {
return nil, err
}
var w io.WriteCloser
switch protocol {
case "smtp", "smtp+insecure", "smtps":
w, err = newSmtpSender(protocol, auth, uri, domain, from, rcpts, requestDSN)
case "jmap":
w, err = newJmapSender(worker, from, rcpts, copyTo)
case "":
w, err = newSendmailSender(uri, rcpts)
default:
err = fmt.Errorf("unsupported protocol %s", protocol)
}
if err != nil {
return nil, err
}
return &crlfWriter{w: w}, nil
}
type crlfWriter struct {
w io.WriteCloser
buf bytes.Buffer
}
func (w *crlfWriter) Write(p []byte) (int, error) {
return w.buf.Write(p)
}
func (w *crlfWriter) Close() error {
defer w.w.Close() // ensure closed even on error
scan := bufio.NewScanner(&w.buf)
for scan.Scan() {
if _, err := w.w.Write(append(scan.Bytes(), '\r', '\n')); err != nil {
return nil
}
}
if scan.Err() != nil {
return scan.Err()
}
return w.w.Close()
}
|