@@ -300,6 +300,78 @@ func TestParseEmail_RFC2047Subject(t *testing.T) {
300300 }
301301}
302302
303+ func TestParseEmail_InlineAttachmentWithCID (t * testing.T ) {
304+ // Build a multipart/related email with an inline image referenced via cid:
305+ raw := []byte ("From: sender@example.com\r \n To: recipient@example.com\r \n Subject: CID Test\r \n " +
306+ "Content-Type: multipart/related; boundary=\" rel\" \r \n \r \n " +
307+ "--rel\r \n Content-Type: text/html\r \n \r \n " +
308+ "<html><body><img src=\" cid:logo123@example.com\" ></body></html>\r \n " +
309+ "--rel\r \n Content-Type: image/png\r \n Content-Disposition: inline; filename=\" logo.png\" \r \n " +
310+ "Content-ID: <logo123@example.com>\r \n Content-Transfer-Encoding: base64\r \n \r \n " +
311+ "iVBORw0KGgo=\r \n " +
312+ "--rel--" )
313+
314+ parsed , atts , err := parseEmail (raw , []string {"recipient@example.com" })
315+ if err != nil {
316+ t .Fatal (err )
317+ }
318+
319+ // HTML should contain the cid: reference (replacement happens in Data(), not parseEmail).
320+ if ! strings .Contains (parsed .HTML , "cid:logo123@example.com" ) {
321+ t .Errorf ("HTML should still contain cid: reference, got %q" , parsed .HTML )
322+ }
323+
324+ // Should have one attachment with ContentID set.
325+ if len (atts ) != 1 {
326+ t .Fatalf ("expected 1 attachment, got %d" , len (atts ))
327+ }
328+ if atts [0 ].ContentID != "logo123@example.com" {
329+ t .Errorf ("ContentID = %q, want %q" , atts [0 ].ContentID , "logo123@example.com" )
330+ }
331+ if atts [0 ].Filename != "logo.png" {
332+ t .Errorf ("Filename = %q, want %q" , atts [0 ].Filename , "logo.png" )
333+ }
334+ }
335+
336+ func TestReplaceCIDReferences (t * testing.T ) {
337+ // Simulate the CID replacement logic from Data().
338+ html := `<html><body><img src="cid:logo@example.com"><img src="cid:banner@example.com"></body></html>`
339+ cidMap := map [string ]string {
340+ "logo@example.com" : "/api/smtp/attachments/evt-uuid/preview/att-uuid-1" ,
341+ "banner@example.com" : "/api/smtp/attachments/evt-uuid/preview/att-uuid-2" ,
342+ }
343+
344+ for cid , url := range cidMap {
345+ html = strings .ReplaceAll (html , "cid:" + cid , url )
346+ }
347+
348+ if strings .Contains (html , "cid:" ) {
349+ t .Errorf ("HTML still contains cid: references: %s" , html )
350+ }
351+ if ! strings .Contains (html , "/api/smtp/attachments/evt-uuid/preview/att-uuid-1" ) {
352+ t .Error ("missing logo preview URL" )
353+ }
354+ if ! strings .Contains (html , "/api/smtp/attachments/evt-uuid/preview/att-uuid-2" ) {
355+ t .Error ("missing banner preview URL" )
356+ }
357+ }
358+
359+ func TestReplaceCIDReferences_NoCID (t * testing.T ) {
360+ // When there are no CID references, HTML should remain unchanged.
361+ html := `<html><body><p>No images</p></body></html>`
362+ cidMap := map [string ]string {}
363+
364+ if len (cidMap ) > 0 {
365+ for cid , url := range cidMap {
366+ html = strings .ReplaceAll (html , "cid:" + cid , url )
367+ }
368+ }
369+
370+ if html != `<html><body><p>No images</p></body></html>` {
371+ t .Errorf ("HTML was modified unexpectedly: %s" , html )
372+ }
373+ }
374+
303375func TestPreviewMapper (t * testing.T ) {
304376 m := & previewMapper {}
305377
0 commit comments