From 86db01792a9ca03fc06c67a973c5ba35be878736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor?= Date: Tue, 24 Nov 2020 10:40:16 +0100 Subject: [PATCH] smtp: fix bcc being ignored * Save all Rcpt command parameters on allReceivers * On Data command, if bccList is empty, compare To and CC with allReceivers * Receivers not referenced by To and CC are BCC --- smtp/smtp.go | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/smtp/smtp.go b/smtp/smtp.go index e5ea9fe..da6bd94 100644 --- a/smtp/smtp.go +++ b/smtp/smtp.go @@ -38,10 +38,11 @@ func formatHeader(h mail.Header) string { } type session struct { - c *protonmail.Client - u *protonmail.User - privateKeys openpgp.EntityList - addrs []*protonmail.Address + c *protonmail.Client + u *protonmail.User + privateKeys openpgp.EntityList + addrs []*protonmail.Address + allReceivers []string } func (s *session) Mail(from string, options smtp.MailOptions) error { @@ -49,9 +50,34 @@ func (s *session) Mail(from string, options smtp.MailOptions) error { } func (s *session) Rcpt(to string) error { + if to == "" { + return nil + } + + // Seems like github.com/emersion/go-smtp/conn.go:487 removes marks on message + // "to" is added into allReceivers blindly + s.allReceivers = append(s.allReceivers, to) return nil } +func (s *session) bccFromRest(ignoreMails []*mail.Address) []*mail.Address { + ignore := make(map[string]struct{}) + for _, mail := range ignoreMails { + ignore[mail.Address] = struct{}{} + } + + final := make([]*mail.Address, 0, len(s.allReceivers)) + for _, addr := range s.allReceivers { + if _, exists := ignore[addr]; exists { + continue + } + final = append(final, &mail.Address{ + Address: addr, + }) + } + return final +} + func (s *session) Data(r io.Reader) error { // Parse the incoming MIME message header mr, err := mail.CreateReader(r) @@ -65,6 +91,10 @@ func (s *session) Data(r io.Reader) error { ccList, _ := mr.Header.AddressList("Cc") bccList, _ := mr.Header.AddressList("Bcc") + if len(bccList) == 0 { + bccList = s.bccFromRest(append(toList, ccList...)) + } + if len(fromList) != 1 { return errors.New("the From field must contain exactly one address") } @@ -353,12 +383,15 @@ func (s *session) Data(r io.Reader) error { return nil } -func (s *session) Reset() {} +func (s *session) Reset() { + s.allReceivers = nil +} func (s *session) Logout() error { s.c = nil s.u = nil s.privateKeys = nil + s.allReceivers = nil return nil } @@ -386,7 +419,12 @@ func (be *backend) Login(_ *smtp.ConnectionState, username, password string) (sm log.Printf("%s logged in", username) - return &session{c, u, privateKeys, addrs}, nil + return &session{ + c: c, + u: u, + privateKeys: privateKeys, + addrs: addrs, + }, nil } func (be *backend) AnonymousLogin(_ *smtp.ConnectionState) (smtp.Session, error) {