Mailgun inline images not displaying on iOS mail app

Viewed 643

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?

1 Answers

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()
Related