Having a weird problem with emails I am sending out via Python email
/ smtplib
.
I am attempting to compose an email with:
The MIME structure is setup like this:
multipart/mixed
multipart/alternative
text/plain
multipart/related
text/html
image/png - inline
application/pdf - attachment
This seems to work fine on every mail client I've tested {BlueMail on Android, iOS mail client, Roundcube} except for the Windows 10 mail client. For some reason, the Windows 10 built-in mail client seems to show the inline image just fine, but shows no trace of the other attachment.
The limited information I have been able to find on the internet points to this being a bug with the Windows 10 mail client, but I have personally received other emails in this client with both inline and attached attachments, which are displayed just fine - so there obviously is some sort of workaround / alternative message structure that works.
My question is thus: How can I format this message differently so that it will show up properly in all relevant mail clients?
I am composing the email like this, in Python:
message = MIMEMultipart("mixed")
message["From"] = ...
.
.
.
bodyText = "..."
bodyHTML = "..."
mailFrom = "..."
targetEmail = "..."
imageContent = ...
messageBody = MIMEMultipart("alternative")
messageBody.attach(MIMEText(bodyText, "plain"))
messageBodyHTML = MIMEMultipart("related")
messageBodyHTML.attach(MIMEText(bodyHTML, "html"))
messageImage = MIMEImage(imageContent)
messageImage.add_header("Content-Disposition", 'inline; filename="..."')
messageImage.add_header("Content-ID", "<id used in html body>")
messageBodyHTML.attach(messageImage)
messageBody.attach(messageBodyHTML)
message.attach(messageBody)
attachment = MIMEApplication(fileContent, Name=fileName)
attachment.add_header("Content-Disposition", 'attachment; filename="..."')
message.attach(attachment)
self.smtplibSession.sendmail(mailSource, targetEmail, message.as_string())
Update: Here's the message data from Windows 10 mail (as output via the "save" feature - there's no way to view the original message raw data that I can find...)
MIME-Version: 1.0
Date: Thu, 30 May 2019 17:45:28 +0200
From: xxxxx <xxxxx>
Subject: xxxxx
Thread-Topic: xxxxx
To: "xxxxx" <xxxxx>
Content-Type: multipart/related;
boundary="_5D6C043C-FD42-42F9-B0E0-841DBFBA96D5_"
--_5D6C043C-FD42-42F9-B0E0-841DBFBA96D5_
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset="utf-8"
<center><img src=3D"cid:embedded-image" alt=...
--_5D6C043C-FD42-42F9-B0E0-841DBFBA96D5_
Content-Type: image/png; name="embedded-image.png"
Content-ID: <embedded-image>
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="embedded-image.png"
iVBORw0KGgoAAAAN...
--_5D6C043C-FD42-42F9-B0E0-841DBFBA96D5_--
I'm not sure if this is a result of saving the email from the app, or this is what the app is actually storing, but it seems that the Windows 10 Mail app is cutting out everything outside the multipart/related
stanza - that is, it's only taking the chosen alternative
and not storing anything else.
For comparison, I've found and exported an email that displayed properly, with an image, html, and attachment, but the format seems to be a lot simpler - that email consisted only of a multipart/mixed
layer with text/html
and an application/pdf
attachment. That email used an external image referenced in the HTML, instead of embedding it in the message - I would like to avoid hosting the images in each email externally.
Unlike you, there was no problem with the attachment file, instead I've had problems in displaying inline images (Windows 10 Mail 16005.11629.20174.0
).
Unfortunately, handling non-standard approaches in MIME messages correctly is a feature that is expected to have good email clients. Apparently Windows 10 Mail is not as "good" yet.
The structure I recommend you to use is:
multipart/mixed
├─── multipart/related
│ ├─── multipart/alternative
│ │ ├─── text/plain
│ │ └─── text/html
│ └─── image/png - inline image
└─── application/pdf - attachment
I've had no problems with this structure in the following clients.
So, give the following code a try to see if it works for you.
message = MIMEMultipart("mixed")
message["From"] = ...
.
.
.
bodyText = "..."
bodyHTML = "..."
mailFrom = "..."
targetEmail = "..."
imageContent = ...
fileContent = ...
relatedBody = MIMEMultipart("related")
messageBody = MIMEMultipart("alternative")
messageBody.attach(MIMEText(bodyText, "plain"))
messageBody.attach(MIMEText(bodyHTML, "html"))
relatedBody.attach(messageBody)
messageImage = MIMEImage(imageContent)
messageImage.add_header("Content-Disposition", 'inline; filename="..."')
messageImage.add_header("Content-ID", "<id used in html body>")
relatedBody.attach(messageImage)
message.attach(relatedBody)
attachment = MIMEApplication(fileContent)
attachment.add_header("Content-Disposition", 'attachment; filename="..."')
message.attach(attachment)