go-mail icon indicating copy to clipboard operation
go-mail copied to clipboard

Occasionally Missing "Content-Disposition: attachment" and Line 1 is "Content-Type: multipart/mixed" instead of Date

Open jameshueston opened this issue 1 year ago • 11 comments

Description

200 EML files were written to disk from uniquely separate IoT devices running the same code over the last several months. 198 were "Good" - opened in Email clients from users on separate domains, viewed attachments & body. 2 were "Bad", meaning

  1. they do not show attachments in Email Clients, and
  2. their body shows multiple equal signs throughout.

The outcome is the same across 3 Email Clients:

  • Microsoft Outlook Desktop version on Windows 11
  • Microsoft Office.com Web version in Chrome Browser
  • Thunderbird Mozilla Desktop on Windows 11

"Good" emails:

  • Line 1 is the Date
  • After "To", has Content-Type: multipart/mixed;
  • After Body's opening boundary, has Content-Transfer-Encoding: quoted-printable
  • 1st attachment has:
    Content-Disposition: attachment; filename="######-XXXXXXXXXXX_XXXXXXXX_XXXXXXXX_MonthEndReport-XXX_X-##.xlsx"
    Content-Transfer-Encoding: base64
    Content-Type: application/octet-stream; name="######-XXXXXXXXXXX_XXXXXXXX_XXXXXXXX_MonthEndReport-XXX_X-##.xlsx"
    
  • 2nd attachment has:
    Content-Disposition: attachment; filename="######-XXXXXXXXXXX_XXXXXXXX_XXXXXXXX_MonthEndReport-XXX_X-##.json"
    Content-Transfer-Encoding: base64
    Content-Type: application/json; name="######-XXXXXXXXXXX_XXXXXXXX_XXXXXXXX_MonthEndReport-XXX_X-##.json"
    

"Bad" emails:

  • Line 1 is Content-Type: multipart/mixed;
  • Line 2 is boundary=[60_character_alpha_numeric] Note this boundary only appears once in the file on Line 2
  • Line 3 is the Date
  • After "To", has Content-Type: multipart/alternative;
  • After Body's opening boundary, has Content-Transfer-Encoding: without a value
  • 1st Attachment has:
    Content-Transfer-Encoding: base64
    Content-Type: application/octet-stream; charset=
    
  • 2nd Attachment has:
    Content-Transfer-Encoding: base64
    Content-Type: application/json; charset=
    
  • Note attachments are missing Content-Disposition: attachment; filename="######-XXX...

All emails (Good and Bad) were built the same - fields REDACTED / refactored for clarity:

msg := mail.NewMsg()
_ = msg.From("[email protected]")
_ = msg.To(REDACTEDConfig.Mail.ToAddresses...)   // which is []string
msg.Subject(getMailSubjectForREDACTED(...))
msg.SetBodyString(getMailBodyForREDACTED(o))

// Attach XLSX file and JSON file
for i := range filepaths {
	msg.AttachFile(filepaths[i], mail.WithFileName(filenames[i]))
}

...

func getMailBodyForREDACTED(o *REDACTED) (ct mail.ContentType, body string) {
	ct = mail.TypeTextPlain

	body = body + "Attached is the REDACTED." + mail.SingleNewLine
	body = body + mail.SingleNewLine
	body = body + "REDACTEDID: " + o.REDACTEDID + mail.SingleNewLine
	...
	// 40 lines total lines building the body as one long string
	
	return
}

To Reproduce

I haven't been able to reproduce this locally yet.

Expected behaviour

All emails would be consistently generated under the "Good" section above.

Screenshots

No response

Attempted Fixes

I haven't done this yet -- and since I haven't been able to recreate yet:

  1. On Msg Body, explicitly set:
    Content-Transfer-Encoding: quoted-printable  // ensure email clients don't print equal signs and wrap at 76 characters; instead treat as continuous text
    Content-Type: text/plain; charset=UTF-8
    
  2. On Excel XLSX Attachment, explicitly set:
    filename="######-MonthlyReport-XXXXXXXX-XXX_X-##.xlsx" // shorter than before
    Content-Transfer-Encoding: base64  // even though base64 is the default
    Content-Type: application/octet-stream // even though this hasn't been misinterpreted
    name="######-MonthlyReport-XXXXXXXX-XXX_X-##.xlsx" // shorter than before
    
  3. On JSON Attachment, explicitly set:
    filename="######-MonthlyReport-XXXXXXXX-XXX_X-##.json"
    Content-Transfer-Encoding: base64
    Content-Type: application/json name="######-MonthlyReport-XXXXXXXX-XXX_X-##.json"
    
  4. Verify after writing to disk:
    1. read the EML from disk
    2. if first four characters are not "Date" OR if "Content-Disposition: attachment"' is not contained, then
      1. Log ERROR
      2. move file with timestamp at end for later debugging
      3. re-generate MSG and write EML again
    3. repeat 1 & 2 again to see if we strike gold

Additional context

No response

jameshueston avatar Jun 04 '24 17:06 jameshueston