13 "github.com/mjl-/mox/dns"
14 "github.com/mjl-/mox/dsn"
15 "github.com/mjl-/mox/mlog"
16 "github.com/mjl-/mox/mox-"
17 "github.com/mjl-/mox/smtpclient"
18 "github.com/mjl-/mox/store"
21// We won't be dialing remote servers. We just connect the smtp port of the first
22// ip in the "local" listener, with fallback to localhost:1025 for any destination
23// address and try to deliver. Our smtpserver uses a mocked dns resolver to give
24// spf/dkim a chance to pass.
25func deliverLocalserve(ctx context.Context, log mlog.Log, msgs []*Msg, backoff time.Duration) {
28 addr := "localhost:1025"
29 l, ok := mox.Conf.Static.Listeners["local"]
30 if ok && l.SMTP.Enabled {
35 addr = net.JoinHostPort(l.IPs[0], fmt.Sprintf("%d", port))
38 dialctx, dialcancel := context.WithTimeout(ctx, 30*time.Second)
40 conn, err := d.DialContext(dialctx, "tcp", addr)
43 failMsgsDB(log, msgs, m0.DialedIPs, backoff, dsn.NameIP{}, err)
49 log.Check(err, "closing connection")
53 clientctx, clientcancel := context.WithTimeout(context.Background(), 60*time.Second)
55 localhost := dns.Domain{ASCII: "localhost"}
56 client, err := smtpclient.New(clientctx, log.Logger, conn, smtpclient.TLSOpportunistic, false, localhost, localhost, smtpclient.Opts{})
59 failMsgsDB(log, msgs, m0.DialedIPs, backoff, dsn.NameIP{}, err)
62 conn = nil // Will be closed when closing client.
65 log.Check(err, "closing smtp client")
68 var msgr io.ReadCloser
70 if len(m0.DSNUTF8) > 0 {
71 msgr = io.NopCloser(bytes.NewReader(m0.DSNUTF8))
72 size = int64(len(m0.DSNUTF8))
78 log.Errorx("opening message for delivery", err, slog.String("remote", addr), slog.String("path", p))
79 err = fmt.Errorf("opening message file: %v", err)
80 failMsgsDB(log, msgs, m0.DialedIPs, backoff, dsn.NameIP{}, err)
83 msgr = store.FileMsgReader(m0.MsgPrefix, f)
86 log.Check(err, "closing message after delivery attempt")
90 deliverctx, delivercancel := context.WithTimeout(context.Background(), 60*time.Second)
92 requireTLS := m0.RequireTLS != nil && *m0.RequireTLS
93 rcpts := make([]string, len(msgs))
94 for i, m := range msgs {
95 rcpts[i] = m.Recipient().String()
97 rcptErrs, err := client.DeliverMultiple(deliverctx, m0.Sender().String(), rcpts, size, msgr, m0.Has8bit, m0.SMTPUTF8, requireTLS)
100 log.Infox("smtp transaction for delivery failed", err)
102 processDeliveries(log, m0, msgs, addr, "localhost", backoff, rcptErrs, err)