Excel file attachment not working with Mailgun API

I’m having trouble sending an Excel file as an attachment through the Mailgun API using Python. The email gets sent successfully but the attachment doesn’t come through. Here’s my current setup:

deliver_email(..., files=["/home/user/report.xlsx"])

And here’s the function that handles the email sending:

def deliver_email(title, content, sender, recipient, files=None):
    
    attachments = []
    if files:
        attachments.extend([("attachment", (os.path.basename(filepath), open(filepath, "rb+", encoding="utf-8"))) for filepath in files])
    
    print(attachments)
    response = requests.post(
        "https://api.mailgun.net/v2/mydomain.com/messages",
        auth=("api", "key-abc123xyz789"),
        files=attachments,
        data={"from": sender,
              "to": recipient,
              "subject": title,
              "text": content}
    )
    return response

The weird thing is that I don’t get any error messages, but when I check the received email, there’s no attachment. Has anyone faced this issue before? What could be causing the attachment to be ignored?

Your file handling’s the problem. You’re opening the Excel file with text encoding, which corrupts binary files like .xlsx. Drop the encoding parameter and use binary mode:

attachments.extend([("attachment", (os.path.basename(filepath), open(filepath, "rb"))) for filepath in files])

Make sure you close the file handles after the request too. I ran into this same issue last year - the file was being read as text instead of binary. Excel files are basically ZIP archives with XML files inside, so they need binary handling. When you force UTF-8 encoding on a binary format, the API gets corrupted data.

I’ve hit this exact issue with email API attachments. The problem’s likely your file object lifecycle - when you open files inside the list comprehension, the handles stay open during the HTTP request, which messes with how Mailgun processes the data. Open and close your files explicitly before building the attachments list. Also check that you’re using absolute file paths and the files actually exist. I’ve seen relative paths work fine locally but fail silently in production, especially when scripts run from different directories.

check your mailgun domain settings - had a similar issue where attachments got filtered by the domain security policy. also, use with open() context manager instead of keeping file handles open during requests. mailgun sometimes drops attachments silently if it cant read them properly.