package imap import ( "encoding/base64" "strings" "testing" ) func TestExtractAttachments_plainAttachment(t *testing.T) { pdfData := []byte("%PDF-1.4\n") raw := buildMultipartMessage(t, "mixed", []mimePart{ { contentType: "text/plain", body: []byte("Hello world"), }, { contentType: "application/pdf; name=\"doc.pdf\"", disposition: "attachment; filename=\"doc.pdf\"", body: pdfData, transferEnc: "base64", }, }) attachments, err := ExtractAttachments(raw) if err != nil { t.Fatalf("ExtractAttachments() error = %v", err) } if len(attachments) != 1 { t.Fatalf("len(attachments) = %d, want 1", len(attachments)) } att := attachments[0] if att.Filename != "doc.pdf" { t.Fatalf("Filename = %q, want doc.pdf", att.Filename) } if att.ContentType != "application/pdf" { t.Fatalf("ContentType = %q, want application/pdf", att.ContentType) } if att.IsInline { t.Fatal("IsInline = true, want false") } if att.ContentID != "" { t.Fatalf("ContentID = %q, want empty", att.ContentID) } if string(att.Data) != string(pdfData) { t.Fatalf("Data = %q, want %q", att.Data, pdfData) } } func TestExtractAttachments_inlineWithCID(t *testing.T) { pngData := []byte{0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n'} raw := buildMultipartMessage(t, "related", []mimePart{ { contentType: "text/html", body: []byte(`
html body
"), }, }) attachments, err := ExtractAttachments(raw) if err != nil { t.Fatalf("ExtractAttachments() error = %v", err) } if len(attachments) != 0 { t.Fatalf("len(attachments) = %d, want 0", len(attachments)) } } type mimePart struct { contentType string disposition string contentID string transferEnc string body []byte } func buildMultipartMessage(t *testing.T, subtype string, parts []mimePart) []byte { t.Helper() const boundary = "test-boundary" var b strings.Builder b.WriteString("From: sender@example.com\r\n") b.WriteString("To: recipient@example.com\r\n") b.WriteString("Subject: attachment test\r\n") b.WriteString("MIME-Version: 1.0\r\n") b.WriteString("Content-Type: multipart/" + subtype + "; boundary=\"" + boundary + "\"\r\n") b.WriteString("\r\n") for _, part := range parts { b.WriteString("--" + boundary + "\r\n") b.WriteString("Content-Type: " + part.contentType + "\r\n") if part.disposition != "" { b.WriteString("Content-Disposition: " + part.disposition + "\r\n") } if part.contentID != "" { b.WriteString("Content-ID: " + part.contentID + "\r\n") } if part.transferEnc != "" { b.WriteString("Content-Transfer-Encoding: " + part.transferEnc + "\r\n") } b.WriteString("\r\n") if part.transferEnc == "base64" { b.WriteString(base64.StdEncoding.EncodeToString(part.body)) } else { b.Write(part.body) } b.WriteString("\r\n") } b.WriteString("--" + boundary + "--\r\n") return []byte(b.String()) }