Python automated Outlook email: change sender or default reply-to address - python

I'm using code similar to Steve Townsend's answer from this question: Send Outlook Email Via Python?
to send an email by running a python script. How can I edit the default reply-to address, so that when someone replies to the automated email it will get sent to a specific address? Alternatively, can I modify the address that the email is sent from? I tried to modify the Msg.SentOnBehalfOfName property but had no success with that. Note that the address is an alias so I can't log into the account in Outlook.
import win32com.client
def send_mail_via_com(text, subject, recipient, profilename="Outlook2003"):
s = win32com.client.Dispatch("Mapi.Session")
o = win32com.client.Dispatch("Outlook.Application")
s.Logon(profilename)
Msg = o.CreateItem(0)
Msg.To = recipient
Msg.CC = "moreaddresses here"
Msg.BCC = "address"
Msg.Subject = subject
Msg.Body = text
attachment1 = "Path to attachment no. 1"
attachment2 = "Path to attachment no. 2"
Msg.Attachments.Add(attachment1)
Msg.Attachments.Add(attachment2)
Msg.Send()

You can try the following code to choose sender address and recipient address freely.
import win32com.client as win32
def send_mail():
outlook_app = win32.Dispatch('Outlook.Application')
# choose sender account
send_account = None
for account in outlook_app.Session.Accounts:
if account.DisplayName == 'sender#hotmail.com':
send_account = account
break
mail_item = outlook_app.CreateItem(0) # 0: olMailItem
# mail_item.SendUsingAccount = send_account not working
# the following statement performs the function instead
mail_item._oleobj_.Invoke(*(64209, 0, 8, 0, send_account))
mail_item.Recipients.Add('receipient#outlook.com')
mail_item.Subject = 'Test sending using particular account'
mail_item.BodyFormat = 2 # 2: Html format
mail_item.HTMLBody = '''
<H2>Hello, This is a test mail.</H2>
Hello Guys.
'''
mail_item.Send()
if __name__ == '__main__':
send_mail()
If you are interesting, you can refer this case.

Related

Define mailbox to which to save an email - win32client python

I would like to save an email to the drafts folder of a shared mailbox using the win32 API for Outlook. I can save an email to my (default?) mailbox drafts folder using the below:
def TestEmailer(text, subject, recipient):
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = recipient
mail.Subject = subject
mail.HtmlBody = text
mail.Save()
TestEmailer('hello world', 'test', 'recipient#gmail.com')
Thanks to this previous question I can see that the SendUsingAccount() method can be used to send from a defined mailbox. Is there an equivalent method for saving to the drafts folder of a defined mailbox?
You can select Save () when you switch your account to send email, which will be saved in the draft box of the new account.
Code:
import win32com.client as win32
def send_mail():
outlook_app = win32.Dispatch('Outlook.Application')
# choose sender account
send_account = None
for account in outlook_app.Session.Accounts:
if account.DisplayName == 'sender#hotmail.com':
send_account = account
break
mail_item = outlook_app.CreateItem(0) # 0: olMailItem
# mail_item.SendUsingAccount = send_account not working
# the following statement performs the function instead
mail_item._oleobj_.Invoke(*(64209, 0, 8, 0, send_account))
mail_item.Recipients.Add('receipient#outlook.com')
mail_item.Subject = 'Test sending using particular account'
mail_item.BodyFormat = 2 # 2: Html format
mail_item.HTMLBody = '''
<H2>Hello, This is a test mail.</H2>
Hello Guys.
'''
mail_item.Save()
if __name__ == '__main__':
send_mail()
Here's a bit of black magic here. Setting mail_item.SendUsingAccount directly won't work. The return value is none. Always send mail from the first email account. You need to call the method of oleobj_.Invoke().
Updated:
Oleobj document: https://github.com/decalage2/oletools/wiki/oleobj
Similar case: python win32com outlook 2013 SendUsingAccount return exception

Cannot set recipients - O365

I'm trying to send e-mail using O365
However I could not find a way to set the Recipient withouth accessing a private attribute.
from O365 import *
my_protocol = MSGraphProtocol(api_version='beta')
account = Account(
credentials=('id', 'id'),
protocol=my_protocol
)
if not account.is_authenticated: # will check if there is a token and has not expired
# ask for a login
account.authenticate(scopes=['mailbox', 'message_send'])
msg = Message(parent=account)
msg.body = 'Hi, foobar.'
msg.subject = 'Bar Foo'
msg.to = Recipient(address='foobar#outlook.com', name='lucas') # dont work
msg._Message__to._recipients = [Recipient(address='foobar#outlook.com', name='lucas')] # works but very bad way i supossed
msg.setRecipients(Recipient(address='foobar#outlook.com', name='lucas')) # some old tutorials used this, but dont work either
msg.send()
This must be a very stupid question, but I read the classes from the doc and could not find a setter for the recipient.
Thanks!
Found it in the github.
msg.to.add('email')
This function add a recipient. Or many if you pass a list of strings.
Final code:
from O365 import *
my_protocol = MSGraphProtocol(api_version='beta')
account = Account(
credentials=('id', 'id'),
protocol=my_protocol
)
if not account.is_authenticated: # will check if there is a token and has not expired
# ask for a login
account.authenticate(scopes=['mailbox', 'message_send'])
msg = Message(parent=account)
msg.body = 'Hi, foobar.'
msg.subject = 'Bar Foo'
msg.to.add('foobar#outlook.com')
msg.send()

Python Outlook headers

I got a script to extract Gmailheaders. There is a lot of information to extract.
When I try to extract data from outlook it feels like im getting a small part.
The script I currently got is:
import win32com.client
import re
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items
message = messages.GetFirst()
rec_time = message.CreationTime
body_content = message.body
while message:
To = message.To
Recipients = message.Recipients
Sender = message.Sender
address = message.Sender.Address
cc = message.CC
Importance = message.Importance
LastModificationTime = message.LastModificationTime
It prints the following fields:
print message.subject
print message.CreationTime
print To
print Sender
print address
print cc
print Importance
print LastModificationTime
Is there just a limit amount of Outlook headers you can extract or?
I've tryed to look on sources like:
https://msdn.microsoft.com/en-us/VBA/Outlook-VBA/articles/mailitem-object-outlook
I am missing important information like sender IP-adresses. Is there anyway of extracting more information without using a 3partytool?
Thanks!
Edit:
Works:
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items
for message in messages:
msg = message.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x007D001F")
To see all MIME headers, read the PR_TRANSPORT_MESSAGE_HEADERS MAPI property (DASL name http://schemas.microsoft.com/mapi/proptag/0x007D001F) using MailItem.PropertyAccessor.GetProperty.
You can see that property (as well as all other MAPI and OOM properties) using OutlookSpy (I am its author) - click IMessage button.

Receive mail from ERP software, change subject and forward

im complete new to this so sorry if this is a stupid question.
Im already searching the whole day for a solution of our problem.
Our Problem: We create an order for our supplier using our ERP software. The supplier want a specific subject in this email to get the mail picked up by there order receive system. We can't set the subject in out ERP software.
Workaround: ERP is sending the mail to an internal address and then we need to change the subject and forward it to the supplier.
We want to do this automatically. is this possible?
I saw a few thing about Python to do this, but not the complete solution. So i know its maybe very nooby, but who can and want to help me.
We are using Novell mail server. (that's also complete new for me :-( )
Update: i've created some code, but its not the best. :)
import smtplib, imaplib, email, re
#mail read, change and forward
imap_host = "SERVERNAME"
client = imaplib.IMAP4('SERVERNAME')
client.login('USERNAME', 'PWD')
client.select('INBOX') #, readonly=True
msgid = 1
status, data = client.fetch(msgid, "(RFC822)")
email_data = data[0][1]
client.close()
client.logout()
message = email.message_from_string(email_data)
message.replace_header("Subject", "test")
message.replace_header("From", 'test#test.com')
message.replace_header("To", 'EXTERN EMAILADRES')
smtp = smtplib.SMTP('SMTP SERVER')
smtp.starttls()
smtp.login('USERNAME', 'PWD')
from_addr = "AFZENDADRES"
to_addr = "EXTERN EMAILADRES"
smtp.sendmail(from_addr, to_addr, message.as_string())
#move mail to folder
client = imaplib.IMAP4('SERVERNAME')
client.login('USERNAME', 'PWD')
client.select('INBOX', readonly=False)
pattern_uid = re.compile('\d+ \(UID (?P<uid>\d+)\)')
def parse_uid(data):
match = pattern_uid.match(data)
return match.group('uid')
resp, items = client.search(None, 'All')
email_ids = items[0].split()
latest_email_id = email_ids[0]
resp, data = client.fetch(latest_email_id, "(UID)")
msg_uid = parse_uid(data[0])
result = client.uid('COPY', msg_uid, 'INBOX/Afgehandeld')
if result[0] == 'OK':
mov, data = client.uid('STORE', msg_uid , '+FLAGS', '(\Deleted)')
client.expunge()
client.close()
client.logout()
Should be fine if this code can be updates so that it checks if there are mails from a sender or with some words in the subject. if there aren't then stop the script. If there are 1 or more mails then we need to change the subject and forward the email to our supplier. Who can help me to get this code better.

Extract sender's email address from Outlook Exchange in Python using win32

I am trying to extract the sender's email address from outlook 2013 using win32 package in python. There are two kinds of email address type in my Inbox, exchange and smtp. If I try to print the the sender's email address of Exchange type, I am getting this:
/O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP(FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=6F467C825619482293F429C0BDE6F1DB-
I have already gone through this link but couldn't find a function through which I can extract the smtp address.
Below is my code:
from win32com.client import Dispatch
outlook = Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder("6")
all_inbox = inbox.Items
folders = inbox.Folders
for msg in all_inbox:
print msg.SenderEmailAddress
Currently all the Email Address are coming like this:
/O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP(FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=6F467C825619482293F429C0BDE6F1DB-
I found a solution to this in VB.net link but don't know how to rewrite the same thing in Python.
Firstly, your code will fail if you have an item other than MailItem in the folder, such as ReportItem, MeetingItem, etc. You need to check that the Class property is 43 (olMail).
Secondly, you need to check the sender email address type and use the SenderEmailAddress property only for the "SMTP" address type. In VB:
for each msg in all_inbox
if msg.Class = 43 Then
if msg.SenderEmailType = "EX" Then
print msg.Sender.GetExchangeUser().PrimarySmtpAddress
Else
print msg.SenderEmailAddress
End If
End If
next
I am just modifying the program given above in Python.
from win32com.client import Dispatch
outlook = Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder("6")
all_inbox = inbox.Items
folders = inbox.Folders
for msg in all_inbox:
if msg.Class==43:
if msg.SenderEmailType=='EX':
print msg.Sender.GetExchangeUser().PrimarySmtpAddress
else:
print msg.SenderEmailAddress
This will print out all the sender's email address in your inbox folders only.
I had this same problem workin with win32com today. I found the solution here.
Using your example it would be:
from win32com.client import Dispatch
outlook = Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder("6")
all_inbox = inbox.Items
folders = inbox.Folders
for msg in all_inbox:
if msg.Class==43:
if msg.SenderEmailType=='EX':
if msg.Sender.GetExchangeUser() != None:
print msg.Sender.GetExchangeUser().PrimarySmtpAddress
else:
print msg.Sender.GetExchangeDistributionList().PrimarySmtpAddress
else:
print msg.SenderEmailAddress
This should solve the group mail issue.

Categories