Python - Sending Outlook email from different address using pywin32
Asked Answered
P

2

6

I have a working script that creates and sends Outlook emails successfully through pywin32, but I would like to send the email from a different, generic account. I have access to this generic account (and password) and even have the mailbox opened concurrently in Outlook, if that helps.

Trying something like msg.From = "[email protected]" returns AttributeError: Property 'CreateItem.From' can not be set..

Is there any way to accomplish this without using SMTP? Even just changing the headers to reflect the generic account as the From and Reply-To address would work.

Edit: Using Win7 32bit, Outlook 2010, python 2.7, and the pywin32 module to create the following bit of code:

from win32com.client import Dispatch
mailer = Dispatch("Outlook.Application")
msg = mailer.CreateItem(0)
msg.To = emailTo
msg.CC = emailCC
msg.Subject = emailSubject
msg.Body = emailBody
msg.Send()

This part works perfectly fine, but it sends the emails through the user that's logged in, myself. I'd rather send it from a generic account so that it looks more official and replies are received there instead of in my mailbox.

Prosector answered 12/6, 2014 at 19:17 Comment(5)
Hi @Yann, I've edited my original comment to include more information and a sample of the code I used. I'm not sure what you're suggesting by using a string varial in a loop; my problem is that it does not appear that I can change the From address at all.Prosector
I would use the internal python email library instead. That works perfectly if you want to send emails.Spidery
@Spidery Can you expand on your suggestion?Prosector
This post pretty much covers it: blog.pythonlibrary.org/2010/05/14/how-to-send-email-with-pythonSpidery
@Spidery Ah, I can't use SMTP.Prosector
W
3

You can send mails via exchange using the extended mapi. It takes a little more effort than what you tried so far but it is very powerful, e.g. it allows to select an outlook profile to be used. Have a look at site-packages\win32comext\mapi\demos\mapisend.py of your pywin32 installation.

EDIT:

As said in the comment, try the following to be sure Outlook is using the profile you want. Look for this line:

session = mapi.MAPILogonEx(0, MAPIProfile, None, mapi.MAPI_EXTENDED |
                           mapi.MAPI_USE_DEFAULT)

and change it to

session = mapi.MAPILogonEx(0, MAPIProfile, None, mapi.MAPI_EXTENDED |
                           mapi.MAPI_LOGON_UI)

Call SendEMAPIMail like this:

SendEMAPIMail(SendSubject, SendMessage, SendTo, MAPIProfile=None)

A dialog should appear offering to select the Outlook profile.

EDIT:

As @caseodilla found out, if Outlook is running with another profile, MAPILogonEx seems to reuse the running session and its profile. In order to force mapi to use another profile add the MAPI_NEW_SESSION flag:

session = mapi.MAPILogonEx(0, MAPIProfile, None, mapi.MAPI_EXTENDED |
                           mapi.MAPI_LOGON_UI | mapi.MAPI_NEW_SESSION)
Warhead answered 3/7, 2014 at 17:12 Comment(8)
I've messed around with extended MAPI a bit. I've even been able to select the profile from which I send the mail, yet it still ends up sending from my user profile address. I'll read further into the information you linked to see what I'm missing.Prosector
I've also forced an installation of the last CDO into my Outlook 2010 environment.Prosector
Try these flags for the MAPILogonEx call: mapi.MAPI_EXTENDED | mapi.MAPI_LOGON_UI and call SendEMAPIMail with MAPIProfile=NoneWarhead
Could you provide a new reply with an example of the kind of code you're suggesting? I'm not following.Prosector
Thanks for the clarification. However, once I implemented your suggested changes, it continued to send from my personal profile. After tinkering around a bit more, I figured some things out. If Outlook is already running, it always sends from that active profile regardless of which profile I have coded. This is good news as relaunching Outlook under the new profile is not a huge hurdle and still doable, but I'd still be interested if there is a way to keep my profile open and code to send from a different address. Your input has been very helpful!Prosector
I can confirm that. Add MAPI_NEW_SESSION to the flags when calling MAPILogonEx and it works - at least partly. Unfortunately the mails seems to be hold back until outlook is launched with the other profile the next time. But that should have a solution I believe.Warhead
Can you add where I have to add what in the original question? I don't get itWaterrepellent
@PV8: It is not possible to choose the profile with the methods of the original question (Simple MAPI). You have to use extended MAPI. This is what my answer is about.Warhead
W
4

I know this comes late, but this is another way I've managed to make this work. With this I was able to send e-mails with my non-default e-mail address in outlook:

import win32com.client as win32

outlook = win32.Dispatch('outlook.application') 

mail = outlook.CreateItem(0)
mail.Subject = "Test subject"
mail.To = "[email protected]"

# If you want to set which address the e-mail is sent from. 
# The e-mail needs to be part of your outlook account.
From = None
for myEmailAddress in outlook.Session.Accounts:
    if "@gmail.com" in str(myEmailAddress):
        From = myEmailAddress
        break

if From != None:
    # This line basically calls the "mail.SendUsingAccount = [email protected]" outlook VBA command
    mail._oleobj_.Invoke(*(64209, 0, 8, 0, From))

    mail.Send()
Wolff answered 23/11, 2020 at 11:55 Comment(3)
Better late than never! Can you elaborate on what this code is doing? Is the for loop necessary, or can I just set what I want the From address to be? Is the magic really just happening in the mail._oleobj_.Invoke?Prosector
outlook.Session.Accounts basically creates a list of every e-mail address that you own in outlook. I then go through them one by one with the for loop to select the one I need. The for loop is not necessary. So for example if you know that the e-mail you want to use is always the very first one you can just use outlook.Session.Accounts[0] (since it is a list). mail._oleobj_.Invoke is when the sender actually gets added to the email. you cant just write your own address as a string instead of the From variable unfortunately, you need to select it from outlook.Session.Accounts.Wolff
So in short, i had only one gmail address in my outlook. I went through each fo them in the forloop and selected the only one which is a gmail account. You can just go ahead and change the "@gmail.com" part to any of your e-mails to apply it as sender.Wolff
W
3

You can send mails via exchange using the extended mapi. It takes a little more effort than what you tried so far but it is very powerful, e.g. it allows to select an outlook profile to be used. Have a look at site-packages\win32comext\mapi\demos\mapisend.py of your pywin32 installation.

EDIT:

As said in the comment, try the following to be sure Outlook is using the profile you want. Look for this line:

session = mapi.MAPILogonEx(0, MAPIProfile, None, mapi.MAPI_EXTENDED |
                           mapi.MAPI_USE_DEFAULT)

and change it to

session = mapi.MAPILogonEx(0, MAPIProfile, None, mapi.MAPI_EXTENDED |
                           mapi.MAPI_LOGON_UI)

Call SendEMAPIMail like this:

SendEMAPIMail(SendSubject, SendMessage, SendTo, MAPIProfile=None)

A dialog should appear offering to select the Outlook profile.

EDIT:

As @caseodilla found out, if Outlook is running with another profile, MAPILogonEx seems to reuse the running session and its profile. In order to force mapi to use another profile add the MAPI_NEW_SESSION flag:

session = mapi.MAPILogonEx(0, MAPIProfile, None, mapi.MAPI_EXTENDED |
                           mapi.MAPI_LOGON_UI | mapi.MAPI_NEW_SESSION)
Warhead answered 3/7, 2014 at 17:12 Comment(8)
I've messed around with extended MAPI a bit. I've even been able to select the profile from which I send the mail, yet it still ends up sending from my user profile address. I'll read further into the information you linked to see what I'm missing.Prosector
I've also forced an installation of the last CDO into my Outlook 2010 environment.Prosector
Try these flags for the MAPILogonEx call: mapi.MAPI_EXTENDED | mapi.MAPI_LOGON_UI and call SendEMAPIMail with MAPIProfile=NoneWarhead
Could you provide a new reply with an example of the kind of code you're suggesting? I'm not following.Prosector
Thanks for the clarification. However, once I implemented your suggested changes, it continued to send from my personal profile. After tinkering around a bit more, I figured some things out. If Outlook is already running, it always sends from that active profile regardless of which profile I have coded. This is good news as relaunching Outlook under the new profile is not a huge hurdle and still doable, but I'd still be interested if there is a way to keep my profile open and code to send from a different address. Your input has been very helpful!Prosector
I can confirm that. Add MAPI_NEW_SESSION to the flags when calling MAPILogonEx and it works - at least partly. Unfortunately the mails seems to be hold back until outlook is launched with the other profile the next time. But that should have a solution I believe.Warhead
Can you add where I have to add what in the original question? I don't get itWaterrepellent
@PV8: It is not possible to choose the profile with the methods of the original question (Simple MAPI). You have to use extended MAPI. This is what my answer is about.Warhead

© 2022 - 2024 — McMap. All rights reserved.