diff --git a/sender/sender.go b/sender/sender.go index db87055c4a5feb4f0f09022c06ff15255bd22662..0a1ac1d6dc711491bd13851cd16724262f4dc3b5 100644 --- a/sender/sender.go +++ b/sender/sender.go @@ -13,6 +13,7 @@ import ( "mime" "mime/multipart" "mime/quotedprintable" + "net/mail" "net/smtp" "net/textproto" "os" @@ -106,6 +107,21 @@ func smtpHelloHostname() string { return hostname } +// extractBareEmail extracts just the email address from a formatted address +// like "Name " or returns the input if it's already bare. +// This is needed for SMTP MAIL FROM command which requires only the email address. +func extractBareEmail(addr string) string { + if addr == "" { + return "" + } + parsed, err := mail.ParseAddress(addr) + if err != nil { + // If parsing fails, return as-is (it might already be bare) + return addr + } + return parsed.Address +} + // generateMessageID creates a unique Message-ID header. func generateMessageID(from string) string { buf := make([]byte, 16) @@ -742,7 +758,7 @@ func SendEmail(account *config.Account, to, cc, bcc []string, subject, plainBody } // Send Envelope - if err = c.Mail(account.GetSendAsEmail()); err != nil { + if err = c.Mail(extractBareEmail(account.GetSendAsEmail())); err != nil { return nil, err } for _, r := range allRecipients { @@ -954,7 +970,7 @@ func SendCalendarReply(account *config.Account, to []string, subject, plainBody } } - if err = c.Mail(account.GetSendAsEmail()); err != nil { + if err = c.Mail(extractBareEmail(account.GetSendAsEmail())); err != nil { return nil, err } for _, r := range to { diff --git a/sender/sender_test.go b/sender/sender_test.go index d6a0efb8db48baca5d323d489bd502495fb8aefe..a323db2474a044274bbf23e110a417381835b12c 100644 --- a/sender/sender_test.go +++ b/sender/sender_test.go @@ -130,3 +130,46 @@ func TestGenerateMessageID(t *testing.T) { t.Errorf("Message-ID has an empty random part, got %s", msgID) } } + +func TestExtractBareEmail(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "bare email", + input: "user@example.com", + expected: "user@example.com", + }, + { + name: "formatted with name", + input: "John Doe ", + expected: "user@example.com", + }, + { + name: "formatted with quoted name", + input: "\"John Doe\" ", + expected: "user@example.com", + }, + { + name: "empty string", + input: "", + expected: "", + }, + { + name: "invalid format returns as-is", + input: "not-an-email", + expected: "not-an-email", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := extractBareEmail(tt.input) + if got != tt.expected { + t.Errorf("extractBareEmail(%q) = %q, want %q", tt.input, got, tt.expected) + } + }) + } +}