Sending Mailgun Inline Images in HTML using Python Requests library
Asked Answered
S

2

10

I am having trouble working out how I can send multiple inline messages using the Mailgun api, from a Python app using the requests library. Currently I have (using jinja2 for templates and flask as the webframework, hosted on Heroku):

def EmailFunction(UserEmail):
    Sender = '[email protected]'
    Subject = 'Hello World'
    Text = ''
    name = re.sub('@.*','',UserEmail)
    html = render_template('GenericEmail.html', name=name)
    images = []
    imageloc = os.path.join(dirname, 'static')
    images.append(open(os.path.join(imageloc,'img1.jpg')))
    images.append(open(os.path.join(imageloc,'img2.jpg')))
    send_mail(UserEmail,Sender,Subject,Text,html,images)
    return html

def send_mail(to_address, from_address, subject, plaintext, html, images):
    r = requests.\
        post("https://api.mailgun.net/v2/%s/messages" % app.config['MAILGUN_DOMAIN'],
            auth=("api", app.config['MAILGUN_KEY']),
             data={
                 "from": from_address,
                 "to": to_address,
                 "subject": subject,
                 "text": plaintext,
                 "html": html,
                 "inline": images
             }
         )
    return r

So the email sends fine, but no images are in the email at the end. When I click to download them they don't show. The images are referenced in the HTML as per the mailgun api (simplified of course!);

<img src="cid:img1.jpg"/>
<img src="cid:img2.jpg"/>
etc ...

Clearly I am doing something wrong, however I tried attaching these using the requests.files object, which didn't even send the email and gave no error so I assume that is not the right way at all.

Sadly the documentation on this is rather sparse.

Would it be better to have the HTML directly point the server side images? However this is not ideal as server side images in general will not be static (some will, some won't).

Scutellation answered 8/3, 2013 at 17:18 Comment(0)
S
20

Sending Inline Images is documented here.

In the HTML, you'll reference the image like this:

<html>Inline image here: <img src="cid:test.jpg"></html>

Then, define a Multidict, to post the files to the API:

files=MultiDict([("inline", open("files/test.jpg"))])

Disclosure, I work for Mailgun. :)

Sallust answered 8/3, 2013 at 20:29 Comment(9)
I'm adding the fact that people from Mailgun answer SO questions as reason #1024 why I love to use Mailgun (I've started 2 companies and worked for a third and all of them on Mailgun)Caddie
I just saw a bug that Mailgun filed about a year ago about this: github.com/kennethreitz/requests/issues/285Caddie
I'm not sure which version fixed this, but it is definitely resolved in later versions, as we rely heavily on Multi Dictionary functionality throughout the API. If you are experiencing this problem, ping me directly and we'll find you a solution.Sallust
Hey, cheers for the help again Travis. Sadly only the first image in the multidict is getting passed to the email. I am using werkzeug.datastructures's MultiDict. However I see on this page documentation.mailgun.net/wrappers.html#python that with the latest version of requests there are issues with passing multidict objects and the work around won't work for files. Unfortunately it seems that as we are passing files an alternative is required. Have you any idea how this could be achieved?Scutellation
Piers - As it turns out... The latest version of Requests does not support Multidict. github.com/kennethreitz/requests/issues/1155. We'll update the documentation on the site to better explain this. For now, I would recommend doing something like this: files=[("inline[1]", open("test.jpg")), ("inline[2]", open("test2.jpg"))]Sallust
Hmm. I'm wondering why 'inline' files still show up as attachments using this method :\Messere
What if the inline image was created using PIL (python imaging library) as opposed to being a file on the server?Headquarters
@TravisSwientek : Could you fix the broken link in your answer please? I bet there's more information than your excellent answer here.Flagrant
How do you reference the image when you're using Django?Huber
S
10

As of 2020, actual documentation here: https://documentation.mailgun.com/en/latest/api-sending.html#examples

My example:

response = requests.post(
    'https://api.mailgun.net/v3/' + YOUR_MAILGUN_DOMAIN_NAME + '/messages',
    auth=('api', YOUR_MAILGUN_API_KEY),
    files=[
        ('inline[0]', ('test1.png', open('path/filename1.png', mode='rb').read())),
        ('inline[1]', ('test2.png', open('path/filename2.png', mode='rb').read()))
    ],
    data={
        'from': 'YOUR_NAME <' + 'mailgun@' + YOUR_MAILGUN_DOMAIN_NAME + '>',
        'to': [adresat],
        'bcc': [bcc_adresat],
        'subject': 'email subject',
        'text': 'email simple text',
        'html': '''<html><body>
            <img src="cid:test1.png">
            <img src="cid:test2.png">
            </body></html>'''
    },
    timeout=5  # sec
)
Sikes answered 23/6, 2020 at 16:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.