Skip to content

Commit 01e7764

Browse files
authored
fix: gmail 555 error when sending (#1496)
## What? Fixed the SMTP "555 5.5.2 Syntax error" that occurred when sending emails with CatchAll enabled by formatting the bare email ## Why? When CatchAll is enabled, the `From` field displays a formatted address like "`Name email@example.com`". This formatted value was being passed directly to Gmail's SMTP MAIL FROM command, which expects only the bare email address. According to RFC 5321 (SMTP protocol), the MAIL FROM command must contain only the mailbox (email address), not a formatted display name. The display name belongs in the message headers (the From: header), which is separate from the SMTP envelope. Fixes #1449 Signed-off-by: drew <me@andrinoff.com>
1 parent f9c5f76 commit 01e7764

2 files changed

Lines changed: 61 additions & 2 deletions

File tree

sender/sender.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"mime"
1414
"mime/multipart"
1515
"mime/quotedprintable"
16+
"net/mail"
1617
"net/smtp"
1718
"net/textproto"
1819
"os"
@@ -106,6 +107,21 @@ func smtpHelloHostname() string {
106107
return hostname
107108
}
108109

110+
// extractBareEmail extracts just the email address from a formatted address
111+
// like "Name <email@example.com>" or returns the input if it's already bare.
112+
// This is needed for SMTP MAIL FROM command which requires only the email address.
113+
func extractBareEmail(addr string) string {
114+
if addr == "" {
115+
return ""
116+
}
117+
parsed, err := mail.ParseAddress(addr)
118+
if err != nil {
119+
// If parsing fails, return as-is (it might already be bare)
120+
return addr
121+
}
122+
return parsed.Address
123+
}
124+
109125
// generateMessageID creates a unique Message-ID header.
110126
func generateMessageID(from string) string {
111127
buf := make([]byte, 16)
@@ -742,7 +758,7 @@ func SendEmail(account *config.Account, to, cc, bcc []string, subject, plainBody
742758
}
743759

744760
// Send Envelope
745-
if err = c.Mail(account.GetSendAsEmail()); err != nil {
761+
if err = c.Mail(extractBareEmail(account.GetSendAsEmail())); err != nil {
746762
return nil, err
747763
}
748764
for _, r := range allRecipients {
@@ -954,7 +970,7 @@ func SendCalendarReply(account *config.Account, to []string, subject, plainBody
954970
}
955971
}
956972

957-
if err = c.Mail(account.GetSendAsEmail()); err != nil {
973+
if err = c.Mail(extractBareEmail(account.GetSendAsEmail())); err != nil {
958974
return nil, err
959975
}
960976
for _, r := range to {

sender/sender_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,46 @@ func TestGenerateMessageID(t *testing.T) {
130130
t.Errorf("Message-ID has an empty random part, got %s", msgID)
131131
}
132132
}
133+
134+
func TestExtractBareEmail(t *testing.T) {
135+
tests := []struct {
136+
name string
137+
input string
138+
expected string
139+
}{
140+
{
141+
name: "bare email",
142+
input: "user@example.com",
143+
expected: "user@example.com",
144+
},
145+
{
146+
name: "formatted with name",
147+
input: "John Doe <user@example.com>",
148+
expected: "user@example.com",
149+
},
150+
{
151+
name: "formatted with quoted name",
152+
input: "\"John Doe\" <user@example.com>",
153+
expected: "user@example.com",
154+
},
155+
{
156+
name: "empty string",
157+
input: "",
158+
expected: "",
159+
},
160+
{
161+
name: "invalid format returns as-is",
162+
input: "not-an-email",
163+
expected: "not-an-email",
164+
},
165+
}
166+
167+
for _, tt := range tests {
168+
t.Run(tt.name, func(t *testing.T) {
169+
got := extractBareEmail(tt.input)
170+
if got != tt.expected {
171+
t.Errorf("extractBareEmail(%q) = %q, want %q", tt.input, got, tt.expected)
172+
}
173+
})
174+
}
175+
}

0 commit comments

Comments
 (0)