I'm stuck trying to add multiple inline images to HTML emails using Mailgun's API and Python's requests library. My Flask app (on Heroku) uses Jinja2 for templates. Here's what I've got:
```python
def send_email(recipient):
sender = '[email protected]'
subject = 'Check out these pics!'
text_content = ''
recipient_name = recipient.split('@')[0]
html_content = render_template('email_template.html', name=recipient_name)
pic_folder = os.path.join(current_dir, 'images')
image_files = [open(os.path.join(pic_folder, f'pic{i}.jpg')) for i in range(1, 3)]
return dispatch_email(recipient, sender, subject, text_content, html_content, image_files)
def dispatch_email(to, from_, subject, text, html, attachments):
response = requests.post(
f'https://api.mailgun.net/v2/{config.MAILGUN_DOMAIN}/messages',
auth=('api', config.MAILGUN_API_KEY),
data={
'from': from_,
'to': to,
'subject': subject,
'text': text,
'html': html,
'inline': attachments
}
)
return response
The email sends, but the images are missing. In the HTML, I’ve used <img src="cid:pic1.jpg"> etc. What am I doing wrong? Should I link to server-side images instead? Help!
I’ve encountered this issue before when working with Mailgun and Python. The problem lies in how you’re handling the image files and the ‘inline’ parameter.
Instead of passing file objects directly, you need to use a list of tuples for the ‘files’ parameter in the requests.post() call. Each tuple should contain the file name, file object, and MIME type.
Modify your dispatch_email function like this:
def dispatch_email(to, from_, subject, text, html, attachments):
files = [('inline', (f'pic{i}.jpg', attachment, 'image/jpeg'))
for i, attachment in enumerate(attachments, 1)]
response = requests.post(
f'https://api.mailgun.net/v2/{config.MAILGUN_DOMAIN}/messages',
auth=('api', config.MAILGUN_API_KEY),
data={
'from': from_,
'to': to,
'subject': subject,
'text': text,
'html': html
},
files=files
)
return response
This should resolve your issue with missing images. Remember to close your file objects after sending the email to prevent resource leaks.
I’ve dealt with a similar issue before, and I think I know what’s going wrong here. The problem is likely in how you’re handling the image files.
When sending inline images with Mailgun, you need to use the ‘inline’ parameter differently. Instead of passing the file objects directly, you should use a list of tuples, where each tuple contains the file object and a filename.
Try modifying your dispatch_email function like this:
def dispatch_email(to, from_, subject, text, html, attachments):
files = [('inline', (f'pic{i}.jpg', attachment, 'image/jpeg')) for i, attachment in enumerate(attachments, 1)]
response = requests.post(
f'https://api.mailgun.net/v2/{config.MAILGUN_DOMAIN}/messages',
auth=('api', config.MAILGUN_API_KEY),
data={
'from': from_,
'to': to,
'subject': subject,
'text': text,
'html': html
},
files=files
)
return response
This approach worked for me in a similar project. Also, make sure your HTML template is using the correct CID format: . If it still doesn’t work, double-check your Mailgun API key and domain settings.