Connect to Exchange mailbox with Python [closed]
Asked Answered
T

4

28

I need to connect to an Exchange mailbox in a Python script, without using any profile setup on the local machine (including using Outlook). If I use win32com to create a MAPI.Session I could logon (with the Logon() method) with an existing profile, but I want to just provide a username & password.

Is this possible? If so, could someone provide example code? I would prefer if it only used the standard library and the pywin32 package. Unfortunately, enabling IMAP access for the Exchange server (and then using imaplib) is not possible.

In case it is necessary: all the script will be doing is connecting to the mailbox, and running through the messages in the Inbox, retrieving the contents. I can handle writing the code for that, if I can get a connection in the first place!

To clarify regarding Outlook: Outlook will be installed on the local machine, but it does not have any accounts setup (i.e. all the appropriate libraries will be available, but I need to operate independently from anything setup inside of Outlook).

Tullus answered 13/11, 2008 at 22:19 Comment(0)
T
1

I'm pretty sure this is going to be impossible without using Outlook and a MAPI profile. If you can sweet talk your mail admin into enabling IMAP on the Exchange server it would make your life a lot easier.

Tawnatawney answered 13/11, 2008 at 22:28 Comment(1)
There is a possiblility you can do what you want with Exchange 2007 using powershell, but I don't know much about it.Tawnatawney
H
149

I know this is an old thread, but...

If you're using Exchange 2007 or newer, or Office365, take a look at Exchange Web Services. It's a pretty comprehensive SOAP-based interface for Exchange, and you can do pretty much anything Outlook is able to do, including delegate or impersonation access to other user accounts.

https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/ews-reference-for-exchange

UPDATE: I have released a Python EWS client on PyPI that supports autodiscover, calendars, inbox, tasks, contacts, and more:

from exchangelib import DELEGATE, Account, Credentials

credentials = Credentials(
    username='MYDOMAIN\\myusername',  # Or [email protected] for O365
    password='topsecret'
)
a = Account(
    primary_smtp_address='[email protected]', 
    credentials=credentials, 
    autodiscover=True, 
    access_type=DELEGATE
)
# Print first 100 inbox messages in reverse order
for item in a.inbox.all().only('subject').order_by('-datetime_received')[:100]:
    print(item.subject)
Hookup answered 18/6, 2010 at 19:21 Comment(15)
+1 as this should be the accepted answer.Flanagan
Is there a python wrapper library that implements that?Bushed
Is this EWS client available in Python 2.7?Caoutchouc
Yes, it supports both Python 2 and 3Hookup
Your library and the sample code that you provided worked flawlessly. Thanks.Kinsler
Does this support proxies @ErikCederstrand ? Cant figure out how to use through proxyConstructive
I must admit I have very little understanding of proxies in an EWS context. Usually, your autodiscover server will just hand out a URL to an EWS endpoint for the account to use. That URL will hide whatever complexity you have internally.Hookup
I have difficulties with the credentials for Office 365. I mainly want to read my emails. So I know my email address and my password. What is MYWINDOMAIN? What is the difference between Credentials and ServiceAccount? Do they have the same username / password?Johanna
For Office365, the username is always the primary SMTP address, AFAIK. So, no WINDOMAIN. Re ServiceAccount, it's the same as Credentials except it implements some automatic backoff policies when the server is failing.Hookup
Unfortunately it seems Exchange Web Services is a thing that needs to be enabled by the server administrator. exchangelib did not let me log in to an Exchange server which was set to use only the MAPI protocol: it just said requests.exceptions.ConnectionError: ('Connection aborted.', BadStatusLine("''",))Byssinosis
Not working for meHannibal
This is awesome! This is a potential game-changer for an IBM i shop like ours!Heptangular
Amazing, still working. How do you download the attachment?Kinser
That’s described in the “Attachments” section of the README.Hookup
This is the way thank youAnaesthesiology
O
31

Ive got it, to connect to outbound exchange you need to connect like this:

import smtplib

url = YOUR_EXCHANGE_SERVER
conn = smtplib.SMTP(url,587)
conn.starttls()
user,password = (EXCHANGE_USER,EXCHANGE_PASSWORD)
conn.login(user,password)

now you can send like a normal connection

message = 'From: FROMADDR\nTo: TOADDRLIST\nSubject: Your subject\n\n{}'
from, to = fromaddr,toaddrs
txt = 'This is my message'
conn.sendmail(fromaddr,toaddrs,msg.format(txt))

to get the mail from your inbox its a little different

import imaplib

url = YOUR_EXCHANGE_URL
conn = imaplib.IMAP4_SSL(url,993)
user,password = (EXCHANGE_USER,EXCHANGE_PASSWORD)
conn.login(user,password)
conn.select('INBOX')
results,data = conn.search(None,'ALL')
msg_ids = data[0]
msg_id_list = msg_ids.split()

this gives you a list of message id' s that you can use to get your emails

latest_email_id = msg_id_list[-1]
result,data = conn.fetch(latest_email_id,"(RFC822)")
raw_email = data[0][1]

now raw_email is your email messsage, but its not very pretty, if you want to parse it do somthing like this

from email.parser import Parser

p = Parser()
msg = p.parsestr(raw_email)

now you can do

msg.get('From')
msg.get('Subject')

or for the content

msg.get_payload()

but if its a multipart message your going to need to do a little more processing, luckly a recursive solution is perfect for this situation

def process_multipart_message(message):
    rtn = ''
    if message.is_multipart():
        for m in message.get_payload():
            rtn += process_multipart_message(m)
    else:
        rtn += message.get_payload()
    return rtn

now

msg_contant = process_multipart_message(msg)

will give you the whole message every time.

Olivia answered 3/6, 2014 at 16:48 Comment(5)
I need to connect to port 443 and set the security to SSL/TLS (accept all certificates). How would I do that? Have been searching for it but no result so far.Codicodices
conn.starttls() before logging inDiabetic
If I need to handle a file that is sent to my email using the script - how can I fetch him? Thanks!!Scampi
This answer does not work if the Exchange server has not been configured to allow IMAP connections.Byssinosis
With Python 3 the email data needs to be decoded from bytes to string. Remediate with something like: raw_email = data[0][1].decode('utf-8')Frannie
T
1

I'm pretty sure this is going to be impossible without using Outlook and a MAPI profile. If you can sweet talk your mail admin into enabling IMAP on the Exchange server it would make your life a lot easier.

Tawnatawney answered 13/11, 2008 at 22:28 Comment(1)
There is a possiblility you can do what you want with Exchange 2007 using powershell, but I don't know much about it.Tawnatawney
L
1

You'll have to find a way to run the process as that particular user.

See this.

I think pywin32.CreateProcessAsUser is the start of the path you need to go down. One last edit. The logged on user handle is obtained from using the win32security.LogonUser method

Lymphocytosis answered 14/11, 2008 at 22:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.