I have the following script that successfully sends mails with images attached to hotmail. The problem is that if I send the same mail to GMAIL the images are attached in the mail and NOT embedded in the HTML. why that happens? how to fix it? As an example, the images inside the HTML appear in the following way:
Here is the current code
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import base64
import email
import smtplib
import os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.header import Header
import codecs
from bs4 import BeautifulSoup
import mimetypes
import requests
import time
SMTP_SERVER = "xxx"
SMTP_PORT = 587
SMTP_USERNAME = "xxx"
SMTP_PASSWORD = "xxx"
SMTP_USE_TLS = False
FROM_EMAIL = "xxx@xxx.com"
lista_mails = ['my_mail@hotmail.com']
lista_apodos =['user']
subject='Test Mail'
def get_image(img_src):
if img_src.startswith('http://') or img_src.startswith('https://'):
try:
resp = requests.get(img_src)
except:
print("Failed to retrieve {}".format(img_src))
print(resp.text)
return None
return MIMEImage(resp.content)
elif os.path.exists(img_src):
fh = open(img_src, 'rb')
image = MIMEImage(fh.read(),'jpeg')
image.add_header('Content-Disposition', 'attachment', filename=os.path.basename(img_src))
fh.close()
return image
return None
def envio_mail(who,nickname,subject):
html = codecs.open("index.html", 'r', 'utf-8').read()
msgRoot = MIMEMultipart('related')
msgRoot['From'] = FROM_EMAIL
msgRoot['Subject'] = subject
msgRoot['To'] = nickname + " <" + who + ">"
soup = BeautifulSoup(html,'lxml')
cid = 0
images = []
for img_element in soup.findAll('img', None):
img_src = img_element.get('src')
image = get_image(img_src)
if image is not None:
image.add_header('Content-ID', str(cid))
images.append(image)
img_element['src'] = "cid:" + str(cid)
cid += 1
for element in soup.findAll(attrs={"background" : True}):
img_src = element.get('background')
image = get_image(img_src)
if image is not None:
image.add_header('Content-ID', str(cid))
images.append(image)
element['background'] = "cid:" + str(cid)
cid += 1
html = str(soup)
msgAlternative = MIMEMultipart('alternative')
msgAlternative.attach(MIMEText(html, "html"))
msgRoot.attach(msgAlternative)
for image in images:
msgRoot.attach(image)
s = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
s.ehlo()
if SMTP_USE_TLS:
s.starttls() #Puts connection to SMTP server in TLS mode
s.ehlo()
s.login(SMTP_USERNAME, SMTP_PASSWORD)
s.sendmail(msgRoot['From'], who, msgRoot.as_string())
s.quit()
envio_mail(lista_mails[0],lista_apodos[0],subject)
You need to attach it and reference it in the HTML. I.e. attach a message with a HTML img that sources the image you've attached.
I see you are well underway, working with the same modules and have a working code, so you should be able get it done with this snippet of code below:
.....
import os
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
.....
# Get the files/images you want to add.
img_dir = "/images"
images = [os.path.join(img_dir, i) for i in os.listdir(img_dir)]
# Added a enumerate loop around the whole procedure.
# Reference to cid:image_id_"j", which you will attach to the email later.
for j, val in enumerate(images):
msgText = MIMEText('<br> <img src="cid:image_id_{}"> </br>'.format(j), 'html')
msgAlternative.attach(msgText)
with open('{}'.format(val), "rb") as attachment:
msgImage = MIMEImage(attachment.read())
# Define the image's ID with counter as you will reference it.
msgImage.add_header('Content-ID', '<image_id_{}>'.format(j))
msgRoot.attach(msgImage)