I'm using Mailgun to send an email with inline images. The following correctly displays the images inline in a browser (and the iOS gmail app), but not on the iOS Mail app.
data = {
'o:dkim': 'yes',
'to': <TO_EMAIL>,
'from': <FROM_EMAIL>,
'html': '<html><img src="cid:inline[0]"></html>',
'subject': 'test',
}
buf = BytesIO()
fig.savefig(buf, format="png") # matplotlib chart
buf.seek(0)
url = "https://api.mailgun.net/v3/%s/messages" % MAILGUN_DOMAIN
r = requests.post(url, data=data, files=[('inline[0]', buf)], auth=('api', <AUTH>))
On the iOS mail app, the image doesn't display (just shows a small square that pops up "Cannot Download Attachment" when I click on it).
Related posts suggest sending a "multipart/related" MIME message, but from inspecting the email in chrome, Mailgun does seem to be doing that part properly - looking at the original message I see:
Mime-Version: 1.0
Content-Type: multipart/related; boundary="edd20bf01a194c43906131936d0ba59e"
Can anyone see what I'm missing?
I found a workaround for this issue. I believe it's to do with the fact that iOS products require an RFC 5322 compliant Message-ID, as mentioned in the django-anymail codebase (which was part of my solution).
Ultimately I probably could have just created a compliant CID, but I reworked my code to incorporate utility functions offered by anymail
and django.core.mail
. Will update if I get around to trying out the former line of investigation.
Here's what I got working:
from anymail.message import attach_inline_image
from django.core.mail import EmailMultiAlternatives
msg = EmailMultiAlternatives(
from_email=<FROM_EMAIL>,
to=<TO_EMAIL>,
subject='test')
buf = BytesIO()
fig.savefig(buf, format="png") # matplotlib chart
buf.seek(0)
buf_id = 0
cid = attach_inline_image(msg, buf.read(), idstring=buf_id, filename=buf_id)
html = '<html><img src="cid:{}"></html>'.format(cid)
msg.attach_alternative(html, "text/html")
msg.send()