M email/send.go => email/send.go +46 -0
@@ 6,6 6,7 @@ import (
"io"
"strconv"
+ "github.com/emersion/go-message"
_ "github.com/emersion/go-message/charset"
"github.com/emersion/go-message/mail"
"github.com/emersion/go-sasl"
@@ 131,3 132,48 @@ func Send(ctx context.Context, msg io.Reader, rcpts []string) error {
}
return err
}
+
+// Sends a raw email. Blocks until it's sent or an error occurs.
+func SendRaw(ctx context.Context, email *message.Entity, to []string) error {
+ worker := ForContext(ctx)
+
+ if worker.client == nil || worker.client.Noop() != nil {
+ worker.client = nil
+
+ c, sender, err := mailSetup(ctx)
+ if err != nil {
+ return err
+ }
+ worker.client = c
+ worker.sender = sender
+ }
+
+ var writer io.WriteCloser
+ var err error
+
+ err = worker.client.Mail(worker.sender.Address, nil)
+ if err != nil {
+ goto end
+ }
+ for _, rcpt := range to {
+ if err := worker.client.Rcpt(rcpt, nil); err != nil {
+ return err
+ }
+ }
+ writer, err = worker.client.Data()
+ if err != nil {
+ goto end
+ }
+ err = email.WriteTo(writer)
+ if err != nil {
+ writer.Close()
+ goto end
+ }
+ err = writer.Close()
+end:
+ if err != nil {
+ worker.client.Close()
+ worker.client = nil
+ }
+ return err
+}
M email/worker.go => email/worker.go +21 -0
@@ 15,6 15,7 @@ import (
work "git.sr.ht/~sircmpwn/dowork"
"github.com/ProtonMail/go-crypto/openpgp"
+ "github.com/emersion/go-message"
_ "github.com/emersion/go-message/charset"
"github.com/emersion/go-message/mail"
"github.com/emersion/go-pgpmail"
@@ 172,6 173,26 @@ func EnqueueStd(ctx context.Context, header mail.Header,
return queue.Enqueue(NewTask(&buf, rcpts))
}
+func EnqueueRaw(ctx context.Context, email *message.Entity, to []string) error {
+ queue := ForContext(ctx).queue
+ return queue.Enqueue(work.NewTask(func(ctx context.Context) error {
+ err := SendRaw(ctx, email, to)
+ if err != nil {
+ log.Printf("Error sending mail: %v", err)
+ }
+ return err
+ }).Retries(10).After(func(ctx context.Context, task *work.Task) {
+ msgID := email.Header.Get("Message-ID")
+ if task.Result() == nil {
+ log.Printf("Mail %s sent to %d recipients after %d attempts",
+ msgID, len(to), task.Attempts())
+ } else {
+ log.Printf("Mail %s failed after %d attempts: %v",
+ msgID, task.Attempts(), task.Result())
+ }
+ }))
+}
+
type nopWriteCloser struct {
io.Writer
}