package smtpserver import ( "strings" "testing" ) // TestParseMessageDecodesBase64Attachment guards against a bug where // mime/multipart.Reader only auto-decodes quoted-printable (not base64), so a // base64-encoded attachment part was stored/read back as raw base64 text instead of // its actual decoded bytes. func TestParseMessageDecodesBase64Attachment(t *testing.T) { raw := "" + "From: sender@example.com\r\n" + "To: rcpt@example.com\r\n" + "Subject: test\r\n" + "MIME-Version: 1.0\r\n" + "Content-Type: multipart/mixed; boundary=\"BOUND\"\r\n" + "\r\n" + "--BOUND\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "hello\r\n" + "--BOUND\r\n" + "Content-Type: application/octet-stream\r\n" + "Content-Disposition: attachment; filename=\"LICENSE\"\r\n" + "Content-Transfer-Encoding: BASE64\r\n" + "\r\n" + "SGVsbG8sIHdvcmxkIQ==\r\n" + "--BOUND--\r\n" parsed, err := parseMessage([]byte(raw)) if err != nil { t.Fatalf("parseMessage: %v", err) } if len(parsed.Attachments) != 1 { t.Fatalf("got %d attachments, want 1", len(parsed.Attachments)) } got := string(parsed.Attachments[0].Data) want := "Hello, world!" if got != want { t.Errorf("attachment data = %q, want %q (decoded from base64, not left as raw base64 text)", got, want) } } // TestParseMessageLeavesNonBase64EncodingsAlone confirms 7bit/8bit/absent // Content-Transfer-Encoding parts pass through unmodified. func TestParseMessageLeavesNonBase64EncodingsAlone(t *testing.T) { raw := "" + "From: sender@example.com\r\n" + "To: rcpt@example.com\r\n" + "Subject: test\r\n" + "MIME-Version: 1.0\r\n" + "Content-Type: multipart/mixed; boundary=\"BOUND\"\r\n" + "\r\n" + "--BOUND\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "hello\r\n" + "--BOUND\r\n" + "Content-Type: text/plain\r\n" + "Content-Disposition: attachment; filename=\"notes.txt\"\r\n" + "Content-Transfer-Encoding: 7bit\r\n" + "\r\n" + "plain text content\r\n" + "--BOUND--\r\n" parsed, err := parseMessage([]byte(raw)) if err != nil { t.Fatalf("parseMessage: %v", err) } if len(parsed.Attachments) != 1 { t.Fatalf("got %d attachments, want 1", len(parsed.Attachments)) } got := strings.TrimSpace(string(parsed.Attachments[0].Data)) if got != "plain text content" { t.Errorf("attachment data = %q, want %q", got, "plain text content") } }