1package smtpserver
2
3import (
4 "context"
5 "fmt"
6
7 "github.com/mjl-/mox/dsn"
8 "github.com/mjl-/mox/mlog"
9 "github.com/mjl-/mox/mox-"
10 "github.com/mjl-/mox/queue"
11 "github.com/mjl-/mox/smtp"
12 "github.com/mjl-/mox/store"
13)
14
15// compose dsn message and add it to the queue for delivery to rcptTo.
16func queueDSN(ctx context.Context, log mlog.Log, c *conn, rcptTo smtp.Path, m dsn.Message, requireTLS bool) error {
17 buf, err := m.Compose(c.log, false)
18 if err != nil {
19 return err
20 }
21 bufDKIM, err := mox.DKIMSign(ctx, c.log, m.From, false, buf)
22 log.Check(err, "dkim signing dsn")
23 buf = append([]byte(bufDKIM), buf...)
24
25 var bufUTF8 []byte
26 if c.smtputf8 {
27 bufUTF8, err = m.Compose(c.log, true)
28 if err != nil {
29 c.log.Errorx("composing dsn with utf-8 for incoming delivery for unknown user, continuing with ascii-only dsn", err)
30 } else {
31 bufUTF8DKIM, err := mox.DKIMSign(ctx, log, m.From, true, bufUTF8)
32 log.Check(err, "dkim signing dsn with utf8")
33 bufUTF8 = append([]byte(bufUTF8DKIM), bufUTF8...)
34 }
35 }
36
37 f, err := store.CreateMessageTemp(c.log, "smtp-dsn")
38 if err != nil {
39 return fmt.Errorf("creating temp file: %w", err)
40 }
41 defer store.CloseRemoveTempFile(c.log, f, "smtpserver dsn message")
42
43 if _, err := f.Write([]byte(buf)); err != nil {
44 return fmt.Errorf("writing dsn file: %w", err)
45 }
46
47 // Queue DSN with null reverse path so failures to deliver will eventually drop the
48 // message instead of causing delivery loops.
49 // ../rfc/3464:433
50 const has8bit = false
51 const smtputf8 = false
52 var reqTLS *bool
53 if requireTLS {
54 reqTLS = &requireTLS
55 }
56 qm := queue.MakeMsg("", smtp.Path{}, rcptTo, has8bit, smtputf8, int64(len(buf)), m.MessageID, nil, reqTLS)
57 qm.DSNUTF8 = bufUTF8
58 if err := queue.Add(ctx, c.log, &qm, f); err != nil {
59 return err
60 }
61 return nil
62}
63