I am newbie to Python. I wanted to send html based email with multiple embedded images
With the following code the email is absolutely working but able to view only one embedded image and another one as undefined
def addMultipleEmbeddedImages(self, nbMsg=1):
attachedFiles = ["giga_logo_300x225.png", "phone_logo.jpg"]
self.imgHtml = ""
for file1 in attachedFiles:
file = os.path.join(pathToAttachments, file1)
self.__msg = MIMEMultipart('related')
self.imgHtml +='<p <u>Embedded Images</u></p><br><img src="cid:%s"><br>'%file
self.__msg.attach(MIMEText(self.imgHtml, 'html'))
fp = open(file, 'rb')
msgImage = MIMEImage(fp.read())
fp.close()
msgImage.add_header('Content-ID', '<%s>'%file)
self.__msg.attach(msgImage)
self.__fillInAddressFields()
# Attach the email in the body
self.__buildBody(self.__msg)
# Send the email with the embedded image
self.__sendMessages(nbMsg)
return
msgImage = MIMEImage(fp.read(),name = os.path.basename(file1))
here i set the name for every image.
Related
I'm making a tool for automatic email with Python and win32com.
I would like to attach files in line spacing due to make mail in RTF.
Accomplishment
Hello, world!
{attached file}
Thank you.
Code
outlook = = win32com.client.Dispatch("Outlook.Application")
mail = outlook.createItemFromTemplate(template_item)
mail.to = ""
mail.cc = ""
mail.bcc = ""
mail.bodyformat = 3 # 3: RTF
mail.Attachment.Add(attachment)
mail.Display(True)
With this code, All files were attached to bottom.
I handled with using 'format' method in mail.Body, but the name of file was inserted.
Could you teach me about the approach to attach files to line spacing in email (RTF)?
mail.to = ""
mail.cc = ""
mail.bcc = ""
mail.bodyformat = 3
mail.Display(True) # before attachment
mail.Attachment.Add(Source=attachment,Position=position)
Changing the "Display" layout, I can attach files in line spacing.
I was looking for an appropriate way to get a specific image from an eml file, but unfortunately, I always get text data without images!
Here is the code I used but it gives me just text data :
from email.parser import BytesParser
from email import policy
with open(em, 'rb') as fp:
name = fp.name # Get file name
msg = BytesParser(policy=policy.default).parse(fp)
data = msg.get_body(preferencelist=('plain')).get_content()
print(data)
fp.close()
do you find any way to solve this? I'm eager to know the method
I have the following code. But somehow only the first image is embedded. The rest of the images is attached to the email. Also, the plain text is not displayed.
Can you help me?
def create_msg2(img_list):
msgRoot = MIMEMultipart('related')
# Set the email subject.
msgRoot['Subject'] = 'This email contain both Html, text and images.'
# Set the email from email address.
msgRoot['From'] = USER
# Set the email to email address.
msgRoot['To'] = TO
# Set the multipart email preamble attribute value. Please refer https://docs.python.org/3/library/email.message.html to learn more.
msgRoot.preamble = '====================================================='
# Create a 'alternative' MIMEMultipart object. We will use this object to save plain text format content.
msgAlternative = MIMEMultipart('alternative')
# Attach the bove object to the root email message.
msgRoot.attach(msgAlternative)
# Create a MIMEText object, this object contains the plain text content.
msgText = MIMEText('This object contains the plain text content of this email.')
# Attach the MIMEText object to the msgAlternative object.
msgAlternative.attach(msgText)
for img in img_list:
image_cid = make_msgid()
# Create a MIMEText object to contains the email Html content. There is also an image in the Html content. The image cid is image1.
msgText = MIMEText('<br><img src="cid:{image_cid}"></br>'.format(image_cid=image_cid[1:-1]), 'html')
# Attach the above html content MIMEText object to the msgAlternative object.
msgAlternative.attach(msgText)
# Open a file object to read the image file, the image file is located in the file path it provide.
with open(img, 'rb') as f:
# Create a MIMEImage object with the above file object.
msgImage = MIMEImage(f.read())
# Add 'Content-ID' header value to the above MIMEImage object to make it refer to the image source (src="cid:image1") in the Html content.
msgImage.add_header('Content-ID', image_cid)
# Attach the MIMEImage object to the email body.
msgRoot.attach(msgImage)
return msgRoot
Ok, this works now. The key is to attach the html string only once
def create_msg(img_list):
msgRoot = MIMEMultipart('related')
today = datetime.today().strftime('%Y-%m-%d')
msgRoot['Subject'] = f'Schlagzeilen, {today}'
msgRoot['From'] = USER
msgRoot['To'] = TO
# Set the multipart email preamble attribute value. Please refer https://docs.python.org/3/library/email.message.html to learn more.
msgRoot.preamble = '====================================================='
# Create a 'alternative' MIMEMultipart object. We will use this object to save plain text format content.
msgAlternative = MIMEMultipart('alternative')
msgRoot.attach(msgAlternative)
msgText = '<html><body><h1>Schlagzeilen</h1><br>'
for img in img_list:
image_cid = make_msgid()
msgText += '<img src="cid:{image_cid}"><br>'.format(image_cid=image_cid[1:-1])
# Open a file object to read the image file
with open(img, 'rb') as f:
msgImage = MIMEImage(f.read())
# Add 'Content-ID' header value to the above MIMEImage object to make it refer to the image source in the Html content.
msgImage.add_header('Content-ID', image_cid)
msgRoot.attach(msgImage)
msgText += '</body></html>'
msgAlternative.attach(MIMEText(msgText, 'html'))
return msgRoot
Does anyone know how to add an email signature to an email using win32com?
import win32com.client as win32
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = 'TO'
mail.Subject = 'SUBJECT'
mail.HTMLbody = 'BODY'
mail.send
A fully functional e-mailer function with signature included, using code from the answer above:
def Emailer(message, subject, recipient):
import win32com.client as win32
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = recipient
mail.Subject = subject
mail.GetInspector
index = mail.HTMLbody.find('>', mail.HTMLbody.find('<body'))
mail.HTMLbody = mail.HTMLbody[:index + 1] + message + mail.HTMLbody[index + 1:]
mail.Display(True)
#mail.send #uncomment if you want to send instead of displaying
then call
Emailer("Hi there, how are you?", "Subject", "david#bisnode.com")
Outlook signatures are not exposed through the Outlook Object Model. The best you can do is read the signature from the file system and add its contents to the HTML body appropriately. Keep in mind that two HTML strings must be merged, not just concatenated. You would also need to merge the styles from two HTML documents and take care of the embedded images used by the signature.
Note that Outlook adds a signature when an unmodified message is displayed or its inspector is touched
import win32com.client as win32
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = 'TO'
mail.Subject = 'SUBJECT'
mail.GetInspector
mail.HTMLBody now contains the message signature that you will need to merger (not just concatenate!) with your own HTML
UPDATE: as of the latest (Summer 2016) builds of Outlook, GetInspector trick no longer works. Now Only MailItem.Display adds the signature to an unmodified message.
If you want to programmatically insert a signature, Redemption (I am its author) exposes RDOSignature object which implements ApplyTo method (it handles the signature image files and merges HTML styles appropriately).
You can find the signature in Outlook stored as an HTML file in %APPDATA%\Microsoft\Signatures and I used the following code to copy the file contents and add them to my email body
import win32com.client
import os
signature_path = os.path.join((os.environ['USERPROFILE']),'AppData\Roaming\Microsoft\Signatures\Work_files\\') # Finds the path to Outlook signature files with signature name "Work"
html_doc = os.path.join((os.environ['USERPROFILE']),'AppData\Roaming\Microsoft\Signatures\Work.htm') #Specifies the name of the HTML version of the stored signature
html_doc = html_doc.replace('\\\\', '\\') #Removes escape backslashes from path string
html_file = codecs.open(html_doc, 'r', 'utf-8', errors='ignore') #Opens HTML file and ignores errors
signature_code = html_file.read() #Writes contents of HTML signature file to a string
signature_code = signature_code.replace('Work_files/', signature_path) #Replaces local directory with full directory path
html_file.close()
olMailItem = 0x0
outlook = win32com.client.Dispatch("Outlook.Application")
newMail = outlook.CreateItem(olMailItem)
newMail.CC = "my#email.com"
newMail.Subject = subject
newMail.BodyFormat = 2 # olFormatHTML https://msdn.microsoft.com/en-us/library/office/aa219371(v=office.11).aspx
newMail.HTMLBody = "Email Message" + signature_code
newMail.display()
It seems I needed to replace the local path to the Signature files, with the absolute path in order to use images,etc.
sig_files_path = 'AppData\Roaming\Microsoft\Signatures\\' + signature_name + '_files\\'
sig_html_path = 'AppData\Roaming\Microsoft\Signatures\\' + signature_name + '.htm'
signature_path = os.path.join((os.environ['USERPROFILE']), sig_files_path) # Finds the path to Outlook signature files with signature name "Work"
html_doc = os.path.join((os.environ['USERPROFILE']),sig_html_path) #Specifies the name of the HTML version of the stored signature
html_doc = html_doc.replace('\\\\', '\\')
html_file = codecs.open(html_doc, 'r', 'utf-8', errors='ignore') #Opens HTML file and converts to UTF-8, ignoring errors
signature_code = html_file.read() #Writes contents of HTML signature file to a string
signature_code = signature_code.replace((signature_name + '_files/'), signature_path) #Replaces local directory with full directory path
html_file.close()
you should be able to do this if your signature is set as default.
>>> signature = message.body
>>> message.body = "ahoj\n" + signature
You acan also use message.HTMLbody if your signature contains picture.
Your signature should always apear in the message if you set it as default. You will save current content of the body to signature variable and then add it to the end of the message. Works for me at least.
I started to apply the code that the good samaritan linktotherescue posted us above.
After doing research on the inspector feature I could make it by doing another signature at Outlook and changing the current image to a text called {IMAGE} then with "Find" I used to search the text and replaced with the image from my original signature.
import win32com.client as win32
import os
import codecs
sig_files_path "C://Users//RenterSa//AppData//Roaming//Microsoft//Signatures//Technical Support Engineer_archivos"
sig_html_path = "C://Users//RenterSa//AppData//Roaming//Microsoft//Signatures//TSE (Python).htm"
img_path = r'C:\Users\RenterSa\AppData\Roaming\Microsoft\Signatures\Technical Support Engineer_archivos\image001.jpg'
signature_path = os.path.join((os.environ['USERPROFILE']), sig_files_path) # Finds the path to Outlook signature files with signature name "Work"
html_doc = os.path.join((os.environ['USERPROFILE']),sig_html_path) #Specifies the name of the HTML version of the stored signature
html_doc = html_doc.replace('\\\\', '\\')
html_file = codecs.open(html_doc, 'r', 'utf-8', errors='ignore') #Opens HTML file and converts to UTF-8, ignoring errors
signature_code = html_file.read() #Writes contents of HTML signature file to a string
signature_code = signature_code.replace((sig_html_path + sig_files_path),
signature_path) #Replaces local directory with full directory path
html_file.close()
olMailItem = 0x0
outlook = win32.Dispatch("Outlook.Application")
newMail = outlook.CreateItem(olMailItem)
newMail.CC = "my#email.com"
newMail.Subject = "subject"
newMail.Importance = 2
newMail.BodyFormat = 3 # olFormatHTML https://msdn.microsoft.com/en-us/library/office/aa219371(v=office.11).aspx
newMail.HTMLBody = "Email Message" + signature_code
inspector = newMail.GetInspector
newMail.display()
doc = inspector.WordEditor
selection = doc.Content
selection.Find.Text = r"{IMAGE}"
selection.Find.Execute()
selection.Text = ""
img = selection.InlineShapes.AddPicture(img_path, 0 , 1)
I have the following code in Python to send an email with an attached pdf.
result_url = '%s%s?analysis_id=%s' % (
constants.HOST_URL, reverse('results'), analysis.id)
pdf_filename = ''.join(['report', str(analysis_id), '.pdf'])
utils.convert_to_pdf(result_url, pdf_filename)
and here is my utils.convert_to_pdf.
def convert_to_pdf(url, filename):
command = "phantomjs export.js %s %s" % (url, filename)
execute_command(command).communicate()
and here is how I am sending the email.
email_ids = []
if analysis.user is not None:
email_ids.append(analysis.user.email)
if email is not None:
email_ids.append(email)
body = ANALYSIS_EMAIL_BODY % (result_url)
try:
message = EmailMultiAlternatives(ANALYSIS_EMAIL_SUBJECT, body, settings.EMAIL_SENDER, email_ids)
message.attach('Report.pdf', pdf_filename, 'application/pdf')
message.send()
except Exception as ex:
logging.error('Send mail failed: %s', ex)
Now I see the PDF file is properly getting generated in my current folder and is attached with the mail but it's size is 0KB in the mail and when I try to open the file it tells .
It may be damaged or use a file format that preview doesn't recognize
What is going wrong here.
You are merely attaching the filename as the contents of the file.
You need to attach the actual contents, not a filename.
message.attach('Report.pdf', read_pdf_contents(), 'application/pdf')
It is your job to determine how to get the raw data from the filename.
It would be something like myfile_like_object.read()