Getting UnicodeDecodeError when sending embedded images with Python requests to Mailgun API

I’m trying to send emails with embedded images using the Mailgun API through Python requests library. The weird thing is that this code works fine on my local machine but fails on a virtual machine with a unicode error.

Here’s my current implementation:

import requests

response = requests.post(
    "https://api.mailgun.net/v2/mydomain.mailgun.org/messages",
    auth=("api", "key-sample123456789"),
    files=[("inline", open("images/photo.png"))],
    data={
        "from": "Test User <[email protected]>",
        "to": "[email protected]",
        "subject": "Test Email",
        "text": "Plain text version",
        "html": '<html><body>Check this image: <img src="cid:photo.png"></body></html>'
    }
)

The error I get is:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 677: ordinal not in range(128)

When I debug this, I can see that the request body contains a string that cannot be properly decoded to unicode. The curl version of this request works without issues, but I really want to stick with the requests library. Has anyone encountered this encoding problem before?

same thing happend to me too. try wraping your file opening in a with statement: with open("images/photo.png", "rb") as f: then use ("inline", f) in the files param. rb mode is key here, otherwise requests gets messed up with encoding.

I ran into the same issue with Mailgun’s API. The problem is how you’re opening the image file. You need to open it in binary mode: open('images/photo.png', 'rb'). Make sure you’re also setting the right MIME type - that’s what fixed the UnicodeDecodeError for me. And don’t forget to close your file handles properly. This worked perfectly across all my different setups.

The environment difference between your local machine and VM is causing this. I’ve seen this exact behavior when default encoding differs between systems. Besides opening the file in binary mode, explicitly specify the content type in your files parameter: files=[('inline', ('photo.png', open('images/photo.png', 'rb'), 'image/png'))]. This three-tuple format tells requests exactly how to handle the file data and prevents encoding ambiguity. Also check your Python version and locale settings on both machines - inconsistent LANG environment variables cause these unicode issues with requests.