This commit is contained in:
parent
8c35d117b2
commit
67b33a28b9
@ -76,6 +76,7 @@ type Email struct {
|
||||
InReplyTo string
|
||||
ThreadReferences string
|
||||
EnvelopeFrom string
|
||||
EnvelopeTo []*User `json:"-"`
|
||||
ReplyTo []*User
|
||||
From *User
|
||||
To []*User
|
||||
|
||||
@ -50,7 +50,7 @@ func (s *Session) prepareNotification(email *parsemail.Email, rawBytes int) erro
|
||||
return &smtp.SMTPError{Code: 550, EnhancedCode: smtp.EnhancedCode{5, 7, 1}, Message: "Notification recipient is not authorized by envelope"}
|
||||
}
|
||||
}
|
||||
if err := s.authorization.ReserveNotification(len(recipients)); err != nil {
|
||||
if err := s.authorization.ReserveNotification(len(s.To)); err != nil {
|
||||
if errors.Is(err, notification.ErrQuota) {
|
||||
return &smtp.SMTPError{Code: 452, EnhancedCode: smtp.EnhancedCode{4, 7, 0}, Message: "Notification sending quota exceeded"}
|
||||
}
|
||||
|
||||
@ -180,6 +180,10 @@ func (s *Session) Data(r io.Reader) (resultErr error) {
|
||||
return send.SendTriggered(ctx, email, "系统通知 SMTP 发信")
|
||||
}
|
||||
}
|
||||
email.EnvelopeTo = make([]*parsemail.User, len(s.To))
|
||||
for index, address := range s.To {
|
||||
email.EnvelopeTo[index] = &parsemail.User{EmailAddress: address}
|
||||
}
|
||||
resultErr = s.deliverOutgoingEmail(email, sender)
|
||||
if resultErr == nil {
|
||||
result = "accepted"
|
||||
|
||||
@ -120,16 +120,23 @@ func sendRecipients(ctx *context.Context, e *parsemail.Email, recipients []*pars
|
||||
return fmt.Errorf("build message: %w", err), nil
|
||||
}
|
||||
|
||||
var to []*parsemail.User
|
||||
to = append(append(append(to, e.To...), e.Cc...), e.Bcc...)
|
||||
if recipients != nil {
|
||||
to = recipients
|
||||
}
|
||||
to := deliveryRecipients(e, recipients)
|
||||
|
||||
return doSend(ctx, fromDomain, b, to, e.From.EmailAddress, trigger)
|
||||
|
||||
}
|
||||
|
||||
func deliveryRecipients(e *parsemail.Email, recipients []*parsemail.User) []*parsemail.User {
|
||||
if recipients != nil {
|
||||
return recipients
|
||||
}
|
||||
if e.EnvelopeTo != nil {
|
||||
return e.EnvelopeTo
|
||||
}
|
||||
var targets []*parsemail.User
|
||||
return append(append(append(targets, e.To...), e.Cc...), e.Bcc...)
|
||||
}
|
||||
|
||||
func parseRecipientAddress(user *parsemail.User) (string, string, error) {
|
||||
if user == nil {
|
||||
return "", "", errors.New("recipient is nil")
|
||||
|
||||
@ -158,3 +158,43 @@ func TestDoSendRejectsEmptyRecipientList(t *testing.T) {
|
||||
t.Fatalf("failure count = %d, want 1", len(failures))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeliveryRecipientsKeepsEnvelopeSeparateFromHeaders(t *testing.T) {
|
||||
to := &parsemail.User{EmailAddress: "header-to@example.com"}
|
||||
cc := &parsemail.User{EmailAddress: "header-cc@example.com"}
|
||||
bcc := &parsemail.User{EmailAddress: "header-bcc@example.com"}
|
||||
envelope := &parsemail.User{EmailAddress: "envelope@example.com"}
|
||||
queued := &parsemail.User{EmailAddress: "queued@example.com"}
|
||||
tests := []struct {
|
||||
name string
|
||||
envelope []*parsemail.User
|
||||
override []*parsemail.User
|
||||
want []*parsemail.User
|
||||
}{
|
||||
{name: "web message uses header recipients", want: []*parsemail.User{to, cc, bcc}},
|
||||
{name: "smtp uses accepted envelope only", envelope: []*parsemail.User{envelope}, want: []*parsemail.User{envelope}},
|
||||
{name: "empty envelope never falls back to headers", envelope: []*parsemail.User{}},
|
||||
{name: "queue uses its single recipient", envelope: []*parsemail.User{envelope}, override: []*parsemail.User{queued}, want: []*parsemail.User{queued}},
|
||||
{name: "explicit empty override never falls back", envelope: []*parsemail.User{envelope}, override: []*parsemail.User{}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
message := &parsemail.Email{
|
||||
To: []*parsemail.User{to}, Cc: []*parsemail.User{cc}, Bcc: []*parsemail.User{bcc},
|
||||
EnvelopeTo: tt.envelope,
|
||||
}
|
||||
got := deliveryRecipients(message, tt.override)
|
||||
if len(got) != len(tt.want) {
|
||||
t.Fatalf("recipient count = %d, want %d", len(got), len(tt.want))
|
||||
}
|
||||
for index := range got {
|
||||
if got[index] != tt.want[index] {
|
||||
t.Fatalf("recipient %d = %v, want %v", index, got[index], tt.want[index])
|
||||
}
|
||||
}
|
||||
if len(message.To) != 1 || message.To[0] != to || len(message.Cc) != 1 || message.Cc[0] != cc || len(message.Bcc) != 1 || message.Bcc[0] != bcc {
|
||||
t.Fatal("delivery routing changed the message headers")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user