Python win32com.client send image embedded in email - python

I am looking to send an image embedded in HTML to send out to a list of senders.
I need to use win32com.client, SMTP is blocked. The image is saved as png and is originally a matplotlib bar chart.
The script successfully sends out the email the recipients cannot see the image embedded in the email. However, I can see the image when I send the email to myself.
I tried to attach the image to the email, still no luck.
email = """<body>
<p><img src="C:\output.png"></p>
</body>
"""
import win32com.client
olMailItem = 0x0
obj = win32com.client.Dispatch("Outlook.Application")
newMail = obj.CreateItem(olMailItem)
newMail.Subject = "the subject"
newMail.HTMLBody = email
newMail.To = "my_email#co.com;outside_email#co.com"
attachment1 = "C:\output.png"
newMail.Attachments.Add(attachment1)
newMail.Send()
Any help greatly appreciated!

In order to display the image in the mail body, use the below code:
mail.Attachments.Add(file_location + 'test.png')
mail.HTMLBody = "<html><body> <img src='cid:test.png'> </body></html>";
Basically if you want to display an attached image in the mail body, you have to refer to it using img src = 'cid:name' , or else it won't be shown.

The distribution list and I have a shared drive. I saved the file in the shared drive and now the receivers of the message can see the image in the email.

I had a similar issue, sending images through the body. Below I have attached the code that fixed it for me.
Code:
email.Display(False) ;
email.Send()

Related

How to send a complete email using smtplib python

I am trying to send an email using Python smtplib.
My objective is to include the below info in email
Attachment file #works fine
Paste the contents of a table in message body #works fine
Write a few lines about the table (as text) in message body # not works. instead stores as an attachment
So, I tried the below code
message = MIMEMultipart()
message['Subject'] = 'For your review - files'
message['From'] = 'user2#org.com'
message['To'] = 'user1#org.com'
# code to paste table contents in outlook message window - works fine
body_content = output # this has the pretty table - html table
message.attach(MIMEText(body_content, "html"))
# code to paste the written text in outlook message window - not works. instead of writing the text in outlook body,it stores as an attachment
written_text = """\
Hi,
How are you?"""
message.attach(MIMEText(written_text, "plain"))
# code to attach an csv file to a outlook email - works fine
with open(filename, "rb") as attachment:
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
f"attachment; filename= {filename}",
)
message.attach(part)
msg_body = message.as_string()
server = SMTP('internal.org.com', 2089)
server.sendmail(message['From'], message['To'], msg_body)
print("mail sent successfully")
server.quit()
The problem in my code is that it creates a text file (containing the message "Hi, How are you") and sends as an attachment?
But I want "Hi, How are you" as a text message in the main Outlook message window.
The immediate problem is that many email clients assume that text body parts after the first are attachments. You can experiment with adding an explicit Content-Disposition: inline to the part(s) you want rendered as part of the main message, but is there a reason these need to be separate body parts in the first place? Combining the text fragments into a single body part would perhaps make more sense here.
More fundamentally, your email code was written for an older Python version. The email module in the standard library was overhauled in Python 3.6 to be more logical, versatile, and succinct; new code should target the (no longer very) new EmailMessage API. Probably throw away this code and start over with modern code from the Python email examples documentation.
from email.message import EmailMessage
message = EmailMessage()
message['Subject'] = 'For your review - files'
message['From'] = 'user2#org.com'
message['To'] = 'user1#org.com'
message.set_content(output, subtype="html")
written_text = """\
Hi,
How are you?"""
message.add_attachment(
written_text, subtype="plain",
disposition="inline")
with open(filename, "rb") as attachment:
message.add_attachment(
attachment.read(),
maintype="application", subtype="octet-stream",
filename=filename)
with SMTP('internal.org.com', 2089) as server:
server.send_message(message)
print("mail sent successfully")
server.quit()
If the final attachment is really a CSV file, specifying it as application/octet-stream is a bit misleading; the proper MIME type would be text/csv (see also What MIME type should I use for CSV?)

Use EMailMessage to to send email with embedded image and multipart text & html read from file

I want to send a multi-part email (text and html) using the Python 3 EMailMessage class, which also has an embedded image. I have been able to get it working when using the MIME classes, but not with the EMailMessage class. The HTML mail shows up but there is no embedded image, with it being added as an attachment instead. Example code is shown below (there are also lines commented out from my various attempts):
# Send an HTML email with an embedded image and a plain text message for
# email clients that don't want to display the HTML.
#Import smtplib for the actual sending function
import smtplib, ssl, mimetypes, imghdr
# Import the email modules we'll need
from email.message import EmailMessage
from email.headerregistry import Address
from email.mime.image import MIMEImage
from email.utils import make_msgid
STR_FROM_DISPLAY_NAME = "From Display Name"
TEXTFILE = "example.txt"
HTMLFILE = "example.html"
IMGFILE = "logo.png"
STR_FROM = "from#example.com"
STR_TO = "to#example.com"
STR_SUBJECT = f"The contents of {TEXTFILE}"
msg = EmailMessage()
msg["Subject"] = STR_SUBJECT
# STR_FROM == the sender's email address
# STR_TO == the recipient's email address
msg["From"] = STR_FROM
msg["To"] = STR_TO
msg.preamble = 'You will not see this in a MIME-aware mail reader.\n'
# Open the plain text file whose name is in TEXTFILE for reading.
with open(TEXTFILE) as fp:
# Create a text/plain message
msg.set_content(fp.read())
# Add the html version. This converts the message into a multipart/alternative
# container, with the original text message as the first part and the new html
# message as the second part.
image_cid = make_msgid()[1:-1] # strip <>
with open(HTMLFILE) as fp:
msg.add_alternative(fp.read(), subtype="html")
#.format(cid=cid), subtype="html")
#maintype, subtype = mimetypes.guess_type(IMGFILE)[0].split('/', 1)
# Now add the related image to the html part.
#attachments={"image1": IMGFILE}
#for png_cid in attachments:
from email.mime.image import MIMEImage
with open(IMGFILE, "rb") as fp:
image_type = imghdr.what(fp.name)
print("image_type = ", image_type)
msgImage = MIMEImage(fp.read())
# Define the image's ID as referenced above
msgImage.add_header("Content-ID", "<image_cid>")
msgImage.add_header('X-Attachment-Id', IMGFILE)
msgImage.add_header("Content-Disposition", f"inline; filename={IMGFILE}")
# msg.attach(msgImage)
# Make the EmailMessage's payload `mixed`
#msg.get_payload()[1].make_mixed() # getting the second part because it is the HTML alternative
#msg.get_payload()[1].attach(msgImage)
msg.get_payload()[1].add_related(msgImage, "image", image_type, fp.name, cid=image_cid) #.format(cid=cid))
# logo = MIMEImage(img.read())
# logo.add_header("Content-ID", f"cid")
# logo.add_header('X-Attachment-Id', IMGFILE)
# logo['Content-Disposition'] = f"inline; filename=" IMGFILE
# msg.attach(logo)
# Make the EmailMessage's payload `mixed`
# msg.get_payload()[1].make_mixed() # getting the second part because it is the HTML alternative
# msg.get_payload()[1].attach(logo)
port = 465 # For starttls
smtp_server = "smtp.mail.server.com"
password = "Password"
# Create secure connection with server and send email
context = ssl.create_default_context()
# Send the message via our own SMTP server.
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
server.login(STR_FROM, password)
server.send_message(msg)
Below is the line from the HTML file where I specify the image:
<img class="image_fix" src="cid:{image_cid}" alt="Logo" title="Logo" width="637" height="213" />
There are lots of examples where the HTML is specified in the python code, but I haven't been able to find any where the HTML is loaded from a file where an image is embedded.
I also want to attach a word .docx file to the email, and I have sort of managed this with MIME classes, but the attachment did not show the size when viewed in the e-mail client. I used the line:
MIMEBase("application", "octet-stream").
with it encoded as base64. I think that there is a "word"/"docx" MIME type, but again not sure how to do it.
Any ideas ?

MIME- sending an email with an HTML file as an attachment?

I am writing a script that creates multiple plotly interactive charts that are saved in HTML format. I want to write code that sends these HTML files out in an email as an attachment. I can't seem to find any documentation on this, only instructions on how to embed the HTML in an email which is not what I want. I just want to attach the file, just like I was attaching a JPG picture or PDF file.
Code I have so far, which just embeds the HTML:
import lxml.html
import smtplib
import sys
import os
page = 'report.html'
root = lxml.html.parse(page).getroot()
root.make_links_absolute()
content = lxml.html.tostring(root)
message = """From: <me#gmail.com>
To: <you#gmail.com>
MIME-Version: 1.0
Content-type: text/html
Subject: %s
%s""" %(page, content)
s = smtplib.SMTP('localhost')
s.sendmail('me#gmail.com', ['you#gmail.com'], message)
s.quit()
Appreciate the help. I'd hopefully like to find a dynamic way to send files that are in multiple formats, so that I don't have to worry about different functions to send different types of files.
In standard documentation see third example with module email
https://docs.python.org/3.6/library/email.examples.html#email-examples
# Import smtplib for the actual sending function
import smtplib
# And imghdr to find the types of our images
import imghdr
# Here are the email package modules we'll need
from email.message import EmailMessage
# Create the container email message.
msg = EmailMessage()
msg['Subject'] = 'Our family reunion'
# me == the sender's email address
# family = the list of all recipients' email addresses
msg['From'] = me
msg['To'] = ', '.join(family)
msg.preamble = 'Our family reunion'
# Open the files in binary mode. Use imghdr to figure out the
# MIME subtype for each specific image.
for file in pngfiles:
with open(file, 'rb') as fp:
img_data = fp.read()
msg.add_attachment(img_data, maintype='image',
subtype=imghdr.what(None, img_data))
# Send the email via our own SMTP server.
with smtplib.SMTP('localhost') as s:
s.send_message(msg)
EDIT: for other files you can get maintype, subtype
import mimetypes
filename = 'file.html'
ctype, encoding = mimetypes.guess_type(filename)
maintype, subtype = ctype.split("/", 1)
print(maintype, subtype)
# text html

I am not able to add an image in email body using python , I am able to add a picture as a attachment but i want a code to add image in mailbody

Right now I am using below code:
import win32com.client as win32
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = 'to address'
mail.Subject = 'Message subject'
mail.Body = 'Message body'
mail.HTMLBody = '<h2>HTML Message body</h2>'# this field is optional
**mail.Attachments.Add('C:\Users\MA299445\Downloads\screenshot.png')**
mail.Send()
I am able to attach a picture but I want to paste this picture in e-mail body.
Thanks in advance
You can use <img> HTML tag:
encoded_image = base64.b64encode(image_file.getvalue()).decode("utf-8")
html = '<img src="data:image/png;base64,%s"/>' % encoded_image
And you can put the tag inside your HTML content.
Don't forget to import required modules:
import base64
Create an attachment and set the PR_ATTACH_CONTENT_ID property (DASL name "http://schemas.microsoft.com/mapi/proptag/0x3712001F") using Attachment.PropertyAccessor.SetProperty.
Your HTML body (MailItem.HTMLBody property) would then need to reference that image attachment through the cid:
<img src="cid:xyz"/>
where xyz is the value of the PR_ATTACH_CONTENT_ID property.
Look at an existing message with OutlookSpy (I am its author) - click IMessage button, go to the GetAttachmentTable tab, double click on an attachment to see its properties.
attachment = mail.Attachments.Add("C:\Users\MA299445\Downloads\screenshot.png")
attachment.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001F", "MyId1")
mail.HTMLBody = "<html><body>Test image <img src=""cid:MyId1""></body></html>"

Python - Send HTML-formatted email via Outlook 2007/2010 and win32com

Is there a way to send HTML-formatted email using Python's win32com.client (which utilizes Outlook 2007/2010). The format I'm using now looks like this:
import win32com.client
olMailItem = 0x0
obj = win32com.client.Dispatch("Outlook.Application")
newMail = obj.CreateItem(olMailItem)
newMail.Subject = "the subject"
newMail.Body = "body text"
newMail.To = "recipient#example.com"
attachment1 = "c:\\mypic.jpg"
newMail.Attachments.Add(attachment1)
newMail.Send()
This will send an email using Outlook, sent from the currently authenticated user, to the specified recipient, with a subject, content, and attached image.
I want to be able to send an inline image, which can be achieved using an "Embedded" attachment, or simply to link to and image using HTML, or embed an image using HTML and a Base64-encoded image.
HTML is my preferred approach, but any HTML I add to the body is formatted and encoded as plain text (e.g. < becomes <). Is there a way to tell Outlook the body content is HTML and should be parsed as such?
This is the way to make the body in html format
newMail.HTMLBody = htmltext

Categories

Resources