I need to use win32com.client to make an email where I add a signature with the .htm extension to the mail.HtmlBody. However, each time I do this, I get UnicodeDecodeError.
In other words, how do I correct the UnicodeDecodeError problem and add my string & htm file to the HtmlBody?
self.mail = win32.Dispatch('outlook.application').CreateItem(0)
self.curText = str(self.email.currentText())
self.projectNameT = ' '.join(self.curText.split(' ')[7:])
self.mail.To = 'ABC#XYZ.com'
self.mail.Subject = "Subject: " + str(self.projectNameT)
self.someStr = 'Hello '
self.html_url = open("SomePath//Signature.htm",encoding = 'utf16')
self.data = self.html_url.read()
self.mail.HtmlBody = self.someStr + ('<p>self.data</p>')
If you want to insert a signature in using python and fully programatically, Redemption exposes the RDOSignature object which implements ApplyTo method (it deals with signature image files and merges HTML styles). Because with the outlook security patch, a lot is unable to be done inherrently, so you must work around this before you can procede as normal
Related
I'm working on code to automate survey participation requests. My current code looks as follows:
def survey_mail(name, receiver, sender):
text_content = f"Hello {name},\r\n
Thank you for participating in my survey via your mail {receiver}\r\n.
You can contact me via {sender}."
html_content = """\ Hello """ + str(name) + """,<br>
Thank you for participating in my survey via your mail """ + str(receiver) + """<br>.
You can contact me via """ + str(sender) + """.
"""
content = MIMEMultipart('alternative')
content.attach(MIMEText(text_content, 'plain'))
content.attach(MIMEText(html_content, 'html'))
...
I have two questions here:
First, would it be possible to import the two string above simply as
template files?
Second, is there a better way to handle variables in the
string? The current method comes with two different ways to format variables: {} vs. """ + var + """.
I tried to insert the two templates as *.txt files, and then load the templates:
with open("text.txt") as f:
text_content = f.read()
with open("html.txt") as f:
html_content = f.read()
However, this did not work. The code does just import the template as a full string.
f-strings are evaluated are definition time, so you cannot read them from a file. The second way in your example (for html) is an expression. While an expression can be eval-ed, it is generally seen as a poor security practice, because it allows execution of uncontrolled code.
But you could just use format as a poor man's templating engine: it have far less features that full fledged template engines, but is enough here.
Example file for the text part:
Hello {name},
Thank you for participating in my survey via your mail {receiver}.
You can contact me via {sender}.
You can then use it that way:
with open("text.txt") as f:
text_content = f.read().format(sender=sender, receiver=receiver)
I've been composing emails in python for thunderbird but I can't seem to set the reply-to field. I've tried the following with a few variations.
I don't get any errors with this method, it composes just fine it just won't fill in the "reply-to" field.
'''
def composeEmail():
import subprocess
tbirdPath = r'c:\Program Files (x86)\Mozilla Thunderbird\thunderbird.exe'
to = 'sendto#somewhere.com'
subject = 'This is my subject'
mBody = 'This is the contents'
replyTo = 'replies#somewhere.com'
body = ('<html><body><h1></h1>%s<br></body></html>' % mBody)
composeCommand = 'format=html,to={},reply-to={},subject={},body={}' .format(to, replyTo, subject, body)
subprocess.Popen([tbirdPath, '-compose', composeCommand])
composeEmail()
'''
Unfortunately, this is not possible. You may want to file a bug here. Only these parameters are available at the moment:
https://hg.mozilla.org/comm-central/file/tip/mailnews/compose/src/nsMsgComposeService.cpp#l1356
I'm trying to extract attachments from .msg files using the following code, as suggested here. Following is just a part of the code to test whether the attachments are read
import email
with open('input/message.msg', 'rb') as fp:
msg = email.message_from_binary_file(fp)
for part in msg.walk():
print(part.get_content_type())
print(part.get_filename())
print(part.get_content_maintype())
I would expect that some of those print statements would output something similar to image/png, but even if that email message has numerous attachments, the output is simply
text/plain
None
text
Do you have any hint of what I'm doing wrong? I'm working on a Linux machine with python 3.7.3.
Thanks
Edit
I didn't investigate too much but I ended up using the python module msg-extractor which, using the following code, works without any problem
import extract_msg
msg = extract_msg.Message("input/email.msg")
for msg in msg.attachments:
print(msg.save())
The attachment class with all the available methods is implement here, I just needed to store the attachments.
I'll keep the question open hoping for a more relevant answer.
Have you had the opportunity to try the MSG PY module from an independent soft company. Here's an example:
from independentsoft.msg import Message
appointment = Message("e:\\appointment.msg")
print("subject: " + str(appointment.subject))
print("start_time: " + str(appointment.appointment_start_time))
print("end_time: " + str(appointment.appointment_end_time))
print("location: " + str(appointment.location))
print("is_reminder_set: " + str(appointment.is_reminder_set))
print("sender_name: " + str(appointment.sender_name))
print("sender_email_address: " + str(appointment.sender_email_address))
print("display_to: " + str(appointment.display_to))
print("display_cc: " + str(appointment.display_cc))
print("body: " + str(appointment.body))
Looked around and couldn't find a satisfactory answer. Does anyone know how to parse .msg files from outlook with Python?
I've tried using mimetools and email.parser with no luck. Help would be greatly appreciated!
This works for me:
import win32com.client
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
msg = outlook.OpenSharedItem(r"C:\test_msg.msg")
print msg.SenderName
print msg.SenderEmailAddress
print msg.SentOn
print msg.To
print msg.CC
print msg.BCC
print msg.Subject
print msg.Body
count_attachments = msg.Attachments.Count
if count_attachments > 0:
for item in range(count_attachments):
print msg.Attachments.Item(item + 1).Filename
del outlook, msg
Please refer to the following post regarding methods to access email addresses and not just the names (ex. "John Doe") from the To, CC and BCC properties - enter link description here
I succeeded extracting relevant fields from MS Outlook files (.msg) using msg-extractor utilitity by Matt Walker.
Prerequesites
pip install extract-msg
Note, it may require to install additional modules, in my case, it required to install imapclient:
pip install imapclient
Usage
import extract_msg
f = r'MS_Outlook_file.msg' # Replace with yours
msg = extract_msg.Message(f)
msg_sender = msg.sender
msg_date = msg.date
msg_subj = msg.subject
msg_message = msg.body
print('Sender: {}'.format(msg_sender))
print('Sent On: {}'.format(msg_date))
print('Subject: {}'.format(msg_subj))
print('Body: {}'.format(msg_message))
There are many other goodies in MsgExtractor utility, to be explored, but this is good to start with.
Note
I had to comment out lines 3 to 8 within the file C:\Anaconda3\Scripts\ExtractMsg.py:
#"""
#ExtractMsg:
# Extracts emails and attachments saved in Microsoft Outlook's .msg files
#
#https://github.com/mattgwwalker/msg-extractor
#"""
Error message was:
line 3
ExtractMsg:
^
SyntaxError: invalid syntax
After blocking those lines, the error message disappeared and the code worked just fine.
Even though this is an old thread, I hope this information might help someone who is looking for a solution to what the thread subject exactly says. I strongly advise using the solution of mattgwwalker in github, which requires OleFileIO_PL module to be installed externally.
I was able to parse it similar way as Vladimir mentioned above. However I needed to make small change by adding a for loop. The glob.glob(r'c:\test_email*.msg') returns a list whereas the Message(f) expect a file or str.
f = glob.glob(r'c:\test_email\*.msg')
for filename in f:
msg = ExtractMsg.Message(filename)
msg_sender = msg.sender
msg_date = msg.date
msg_subj = msg.subject
msg_message = msg.body
I found on the net a module called MSG PY.
This is Microsoft Outlook .msg file module for Python.
The module allows you to easy create/read/parse/convert Outlook .msg files.
The module does not require Microsoft Outlook to be installed on the machine or any other third party application or library in order to work.
For example:
from independentsoft.msg import Message
appointment = Message("e:\\appointment.msg")
print("subject: " + str(appointment.subject))
print("start_time: " + str(appointment.appointment_start_time))
print("end_time: " + str(appointment.appointment_end_time))
print("location: " + str(appointment.location))
print("is_reminder_set: " + str(appointment.is_reminder_set))
print("sender_name: " + str(appointment.sender_name))
print("sender_email_address: " + str(appointment.sender_email_address))
print("display_to: " + str(appointment.display_to))
print("display_cc: " + str(appointment.display_cc))
print("body: " + str(appointment.body))
I've tried the python email module and sometimes that doesn't successfully parse the msg file.
So, in this case, if you are only after text or html, the following code worked for me.
start_text = "<html>"
end_text = "</html>"
def parse_msg(msg_file,start_text,end_text):
with open(msg_file) as f:
b=f.read()
return b[b.find(start_text):b.find(end_text)+len(end_text)]
print parse_msg(path_to_msg_file,start_text,end_text)
The extract-msg Python module (pip install extract-msg) is also extremely useful because it allows quick access to the full headers from the message, something that Outlook makes much harder than necessary to get hold of.
My modification of Vladimir's code that shows full headers is:
#!/usr/bin/env python3
import extract_msg
import sys
msg = extract_msg.Message(sys.argv[1])
msg_sender = msg.sender
msg_date = msg.date
msg_subj = msg.subject
print('Sender: {}'.format(msg_sender))
print('Sent On: {}'.format(msg_date))
print('Subject: {}'.format(msg_subj))
print ("=== Details ===")
for k, v in msg.header.items():
print("{}: {}".format(k, v))
print(msg.body)
I want to send a zip file through SOAP (from a SOAP client to a SOAP server) in python.
Following the reading of this SO question, I choose to use suds as my python client.
But according to this, suds do not support sending attachment. A method is given to circumvent the problem but I've not been able to make it work. I'm puzzled over what I'm supposed to give as parameters.
Anyone know how to send a file through Soap in python ?
If needed I'll switch to another SOAP client library.
Download the provided wrapper, and then where you would normally say something like...
client.service.fooMethod(fooParam1,fooParam2,...)
...instead do...
soap_attachments.with_soap_attachment(client.service.fooMethod,binaryParam,fooParam1,fooParam2,...)
Where binaryParam is of the type expected by soap_attachements.py. For example, if you wanted to send a png image I think (never done this) you would do:
imageFile = open('imageFile.png','rb')
imageData = imageFile.read()
mimeType = 'image/png'
binaryParam = (imageData, uuid.uuid4(), mimeType)
Attachments are best way to send binary file through SOAP. If you can't use any other method but only SOAP, just encode your binaries with Base64 and paste it into SOAP method as a parameter. It isn't pure, but works great with small attachments. Large binaries? Use FTP, WebDAV and all others native ways for sending files between hosts.
I made the following changes to soap_attachments.py under suds to get my own uploads to work. You may not need some of the changes that I've made to this, but hopefully it'll at least give you a start.
--- /home/craig/Downloads/soap_attachments.py 2011-07-08 20:38:55.708038918 -0400
+++ soap_attachments.py 2011-06-21 10:29:50.090243052 -0400
## -1,4 +1,8 ##
+import uuid
+import re
def with_soap_attachment(suds_method, attachment_data, *args, **kwargs):
+ HUD_ARM_SERVICE_URL = suds_method.client.wsdl.url
+ HUD_ARM_SERVICE_URL = HUD_ARM_SERVICE_URL.replace('wsdl','xsd')
""" Add an attachment to a suds soap request.
attachment_data is assumed to contain a list:
## -16,7 +20,9 ##
soap_method = suds_method.method
if len(attachment_data) == 3:
+ print "here"
data, attachment_id, attachment_mimetype = attachment_data
+ attachment_id = uuid.uuid4()
elif len(attachment_data) == 2:
data, attachment_id = attachment_data
attachment_mimetype = MIME_DEFAULT
## -55,7 +61,7 ##
])
# Build the full request
- request_text = '\n'.join([
+ request_text = '\r\n'.join([
'',
'--%s' % boundary_id,
soap_headers,
I then use:
f = open(dir_path + infile,'rb')
data_file = f.read()
data_file_type = mimetypes.guess_type(infile)[0]
(filename,ext) = infile.split('.')
...
clientargs = [...]
identifier = with_soap_attachment(client.service.fooThing, [data_file, '1', data_file_type], credentials['foo'],credentials['bar'], morefoo)
You might not need all of these changes, but it's what got me going.
Hope this helps!