go-mail
go-mail copied to clipboard
Occasionally Missing "Content-Disposition: attachment" and Line 1 is "Content-Type: multipart/mixed" instead of Date
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
- they do not show attachments in Email Clients, and
- 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:
- 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 - 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 - 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" - Verify after writing to disk:
- read the EML from disk
- if first four characters are not "Date" OR if "Content-Disposition: attachment"' is not contained, then
- Log ERROR
- move file with timestamp at end for later debugging
- re-generate MSG and write EML again
- repeat 1 & 2 again to see if we strike gold
Additional context
No response