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