8	"golang.org/x/exp/slog"
 
10	"github.com/mjl-/mox/dns"
 
11	"github.com/mjl-/mox/mlog"
 
12	"github.com/mjl-/mox/smtp"
 
15// From extracts the address in the From-header.
 
17// An RFC5322 message must have a From header.
 
18// In theory, multiple addresses may be present. In practice zero or multiple
 
19// From headers may be present. From returns an error if there is not exactly
 
20// one address. This address can be used for evaluating a DMARC policy against
 
21// SPF and DKIM results.
 
22func From(elog *slog.Logger, strict bool, r io.ReaderAt) (raddr smtp.Address, envelope *Envelope, header textproto.MIMEHeader, rerr error) {
 
23	log := mlog.New("message", elog)
 
27	// todo: only allow utf8 if enabled in session/message?
 
29	p, err := Parse(log.Logger, strict, r)
 
31		// todo: should we continue with p, perhaps headers can be parsed?
 
32		return raddr, nil, nil, fmt.Errorf("parsing message: %v", err)
 
34	header, err = p.Header()
 
36		return raddr, nil, nil, fmt.Errorf("parsing message header: %v", err)
 
38	from := p.Envelope.From
 
40		return raddr, nil, nil, fmt.Errorf("from header has %d addresses, need exactly 1 address", len(from))
 
42	d, err := dns.ParseDomain(from[0].Host)
 
44		return raddr, nil, nil, fmt.Errorf("bad domain in from address: %v", err)
 
46	addr := smtp.Address{Localpart: smtp.Localpart(from[0].User), Domain: d}
 
47	return addr, p.Envelope, textproto.MIMEHeader(header), nil