103

I am using Outlook 2003.

What is the best way to send email (through Outlook 2003) using Python?

user3262424
  • 7,223
  • 16
  • 54
  • 84
  • 2
    @ThiefMaster: my `smtp` server is not the same as my email -- hence, I need to `channel` my smtp through my internet provider (`att`), even though I am using a different email address (not `att's`) to send the email. `Outlook` is already configured to handle this. If there are other solutions (non-`Outlook` based) that will also support this, I'd be happy to hear suggestions. – user3262424 Jun 13 '11 at 18:11
  • The proper solution is using python's [smtplib](http://docs.python.org/library/smtplib.html#smtp-example) – ThiefMaster Jun 13 '11 at 18:35

9 Answers9

225
import win32com.client as win32
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = 'To address'
mail.Subject = 'Message subject'
mail.Body = 'Message body'
mail.HTMLBody = '<h2>HTML Message body</h2>' #this field is optional

# To attach a file to the email (optional):
attachment  = "Path to the attachment"
mail.Attachments.Add(attachment)

mail.Send()

Will use your local outlook account to send.

Note if you are trying to do something not mentioned above, look at the COM docs properties/methods: https://msdn.microsoft.com/en-us/vba/outlook-vba/articles/mailitem-object-outlook. In the code above, mail is a MailItem Object.

TheoretiCAL
  • 19,461
  • 8
  • 43
  • 65
  • Is it possible to an html body. Like an email body with pictures – Aakash Gupta Dec 09 '16 at 10:03
  • 3
    Updated answer. mail.HTMLBody lets you set it to a string of html – TheoretiCAL Dec 09 '16 at 17:59
  • 7
    Simple and straight answer! Working correctly in Python 3.6.1. – abautista Jun 21 '17 at 14:00
  • How can i request a delivery receipt with win32com? – Viktor Demin Sep 25 '17 at 13:43
  • 1
    @ViktorDemin Looking at the official COM docs, https://msdn.microsoft.com/en-us/vba/outlook-vba/articles/mailitem-readreceiptrequested-property-outlook, I would try mail.ReadReceiptRequested = True – TheoretiCAL Sep 25 '17 at 17:25
  • how to add multiple email address for a single mail? – Pyd Nov 09 '18 at 04:31
  • 3
    @pyd try simply a colon seperated string of emails in the `mail.To = "a@b.com;c@d.com"`, let me know if it works – TheoretiCAL Nov 09 '18 at 19:06
  • @TheoretiCAL Is it possible to forward an existing outlook mail that I saved as `.msg` and insert Bcc, To and Subject? I save e-mails as .msg in my folder and want to send that. I tried to modify `mail = outlook.CreateItem(0)` without success. – Mataunited18 Apr 04 '19 at 08:17
  • any way to change the senders adress or hide it? – PV8 Oct 11 '19 at 09:46
  • @TheoretiCAL Thank you for this answer. it really helps but I think there is not option available for CC and Bcc in this Example?How to use CC and Bcc here? also if we want to copy and paste Excel data in email than how we can do that? – Vishav Gupta Jun 02 '20 at 10:35
  • @TheoretiCAL the outlook object has an `ItemSend` event. Can it be used to detect when the MailObject has been sent? I will like to call `Quit()` on the application object when the email has been sent. The attachment of the mail causes delays in it sending. I don't want to call quit right after `MailItem.Send()` – Charitoo Jun 22 '20 at 09:04
  • Cant create item other than 0x0. Meet = outlook.CreateItem(1) Gives the error:AttributeError: Property 'CreateItem.To' can not be set. I'm trying to create a olAppointmentItem – Rahul Raj Purohit Jun 26 '20 at 19:31
  • win32 is so dang good. what is the best way to learn this package? – Ukrainian-serge Aug 18 '20 at 18:10
  • 1
    @Ukrainian-serge look at https://pbpython.com/windows-com.html and https://learn.microsoft.com/de-de/windows/win32/com/component-object-model--com--portal?redirectedfrom=MSDN – Oliver Hoffmann Jan 14 '21 at 12:06
  • Works right out of the box. Thank you @TheoretiCAL ! – Tambe Tabitha Feb 17 '23 at 04:02
  • Can this method be used to send from another outlook account? – Theo F Jun 12 '23 at 22:20
47

For a solution that uses outlook see TheoretiCAL's answer.

Otherwise, use the smtplib that comes with python. Note that this will require your email account allows smtp, which is not necessarily enabled by default.

SERVER = "smtp.example.com"
FROM = "yourEmail@example.com"
TO = ["listOfEmails"] # must be a list

SUBJECT = "Subject"
TEXT = "Your Text"

# Prepare actual message
message = """From: %s\r\nTo: %s\r\nSubject: %s\r\n\

%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)

# Send the mail
import smtplib
server = smtplib.SMTP(SERVER)
server.sendmail(FROM, TO, message)
server.quit()

EDIT: this example uses reserved domains like described in RFC2606

SERVER = "smtp.example.com"
FROM = "johnDoe@example.com"
TO = ["JaneDoe@example.com"] # must be a list

SUBJECT = "Hello!"
TEXT = "This is a test of emailing through smtp of example.com."

# Prepare actual message
message = """From: %s\r\nTo: %s\r\nSubject: %s\r\n\

%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)

# Send the mail
import smtplib
server = smtplib.SMTP(SERVER)
server.login("MrDoe", "PASSWORD")
server.sendmail(FROM, TO, message)
server.quit()

For it to actually work with gmail, Mr. Doe will need to go to the options tab in gmail and set it to allow smtp connections.

Note the addition of the login line to authenticate to the remote server. The original version does not include this, an oversight on my part.

Adriaan
  • 17,741
  • 7
  • 42
  • 75
Spencer Rathbun
  • 14,510
  • 6
  • 54
  • 73
  • 15
    This was not the question. The question is about using the Win32 API in order to control Outlook –  Jun 13 '11 at 15:38
  • @Spencer Rathbun: thank you. The problem is this: my `smtp` server is not the same as my email -- hence, I need to `channel` my smtp through my internet provider (`att`), even though I am using a different email address (not `att's`) to send the email. `Outlook` is already configured to handle this. If there are other solutions (non-`Outlook` based) that will also support this, I'd be happy to hear suggestions. – user3262424 Jun 13 '11 at 18:12
  • 1
    @user3262424 So your email address is not the same as your smtp server? That should be handled on the smtp server. It needs to be set to pass on emails that don't originate there to the proper email server. Incorrectly set up, this allows spammers to loop through you. But presumably, you know the ip addresses involved and can set them on an allow list. – Spencer Rathbun Jun 13 '11 at 18:24
  • @Spencer Rathbun: thank you, but I am not sure how to use your script. I am not successful sending an email using it. – user3262424 Jun 13 '11 at 18:47
  • @user3262424 Most of the problems I've had with this thing involve settings on the server side. If the script gets to the server.sendmail line and hangs for a bit, then reports an error, you have a server settings issue. The error will help with debugging the problem.You say though that outlook is already set up to use the smtp server, in which case you should be able to use the settings outlook has for everything. If the server is bouncing you, it just means that you need to allow smtp on it. What smtp server are you using? – Spencer Rathbun Jun 13 '11 at 18:54
  • @Spencer Rathbun: I am using an email that is associated with a domain I purhcased. Yet, in order to connect to send emails, I need to connect to the `att` smtp server (rather than to the servers where my domain is hosted). the connection to the `att` server requires me to authenticate my outgoing emails using my `att` user & password (even though I don't use the `att` email!). `outlook` is setup to handle this (allowing outgoing messages to be authenticated through a different provider, in this case, `att`). I do not know how to provide this info to `smtplib` to do the same. – user3262424 Jun 13 '11 at 20:09
  • @user3262424 If you have email in the domain you purchased, it has it's own email server. Your `att` server is just set up to pass the emails it receives onwards to the email on the domain. In that case, the simpler thing to do is find out the name of mail server hosting your email from Tech Support. Let them know you want to send using smtp and they should be able to direct you through turning on smtp at the server, then just replace the server name with the one they give you. I've edited to show an example with google mail. – Spencer Rathbun Jun 13 '11 at 20:20
  • Using `email` and `smtplib` together is [recommended by Escualo in this excellent answer](http://stackoverflow.com/a/6270987/994153). – Colin D Bennett Aug 01 '14 at 18:22
  • 5
    If you are, God forbid, behind a corporate firewall, you can only send mail via Outlook. – Prof. Falken Feb 21 '17 at 19:14
  • What should I give for sever name in the first line for outlook? – suchitra nagarajan Apr 22 '20 at 23:40
11

I wanted to send email using SMTPLIB, its easier and it does not require local setup. After other answers were not directly helpful, This is what i did.

Open Outlook in a browser; Go to the top right corner, click the gear icon for Settings, Choose 'Options' from the appearing drop-down list. Go to 'Accounts', click 'Pop and Imap', You will see the option: "Let devices and apps use pop",

Choose Yes option and Save changes.

Here is the code there after; Edit where neccesary. Most Important thing is to enable POP and the server code herein;

import smtplib

body = 'Subject: Subject Here .\nDear ContactName, \n\n' + 'Email\'s BODY text' + '\nYour :: Signature/Innitials'
try:
    smtpObj = smtplib.SMTP('smtp-mail.outlook.com', 587)
except Exception as e:
    print(e)
    smtpObj = smtplib.SMTP_SSL('smtp-mail.outlook.com', 465)
#type(smtpObj) 
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.login('me@outlook.com', "password") 
smtpObj.sendmail('sender@outlook.com', 'recipient@gmail.com', body) # Or recipient@outlook

smtpObj.quit()
pass
Edison
  • 870
  • 1
  • 13
  • 28
8

using pywin32:

from win32com.client import Dispatch

session = Dispatch('MAPI.session')
session.Logon('','',0,1,0,0,'exchange.foo.com\nUserName');
msg = session.Outbox.Messages.Add('Hello', 'This is a test')
msg.Recipients.Add('Corey', 'SMTP:corey@foo.com')
msg.Send()
session.Logoff()
Corey Goldberg
  • 59,062
  • 28
  • 129
  • 143
7

A simple solution for Office 365 is

from O365 import Message

html_template =     """ 
            <html>
            <head>
                <title></title>
            </head>
            <body>
                    {}
            </body>
            </html>
        """

final_html_data = html_template.format(df.to_html(index=False))

o365_auth = ('sender_username@company_email.com','Password')
m = Message(auth=o365_auth)
m.setRecipients('receiver_username@company_email.com')
m.setSubject('Weekly report')
m.setBodyHTML(final)
m.sendMessage()

Here df is a dataframe converted to an html Table, which is being injected into html_template

Adriaan
  • 17,741
  • 7
  • 42
  • 75
Gil Baggio
  • 13,019
  • 3
  • 48
  • 37
  • ```ValueError: Protocol not provided to Api Component```. Nice lib, but I'm still trying to find how to auth the code. – wolfpan Feb 08 '23 at 15:45
7

This is a pretty old question but there is one more solution. The current Outlook SMTP server is (as of 2022):

  • Host: smtp.office365.com
  • Port: 587 (for TLS)

Probably the easiest and cleanest solution is to use Red Mail that has these already set:

pip install redmail

Then:

from redmail import outlook

outlook.user_name = "example@hotmail.com"
outlook.password = "<MY PASSWORD>"

outlook.send(
    receivers=["you@example.com"],
    subject="An example",
    text="Hi, this is an example."
)

Red Mail supports all sorts of advanced features:

Links:

Disclaimer: I'm the author

miksus
  • 2,426
  • 1
  • 18
  • 34
2

This was one I tried using Win32:

import win32com.client as win32
import psutil
import os
import subprocess
import sys

# Drafting and sending email notification to senders. You can add other senders' email in the list
def send_notification():


    outlook = win32.Dispatch('outlook.application')
    olFormatHTML = 2
    olFormatPlain = 1
    olFormatRichText = 3
    olFormatUnspecified = 0
    olMailItem = 0x0

    newMail = outlook.CreateItem(olMailItem)
    newMail.Subject = sys.argv[1]
    #newMail.Subject = "check"
    newMail.BodyFormat = olFormatHTML    #or olFormatRichText or olFormatPlain
    #newMail.HTMLBody = "test"
    newMail.HTMLBody = sys.argv[2]
    newMail.To = "xyz@abc.com"
    attachment1 = sys.argv[3]
    attachment2 = sys.argv[4]
    newMail.Attachments.Add(attachment1)
    newMail.Attachments.Add(attachment2)

    newMail.display()
    # or just use this instead of .display() if you want to send immediately
    newMail.Send()





# Open Outlook.exe. Path may vary according to system config
# Please check the path to .exe file and update below
def open_outlook():
    try:
        subprocess.call(['C:\Program Files\Microsoft Office\Office15\Outlook.exe'])
        os.system("C:\Program Files\Microsoft Office\Office15\Outlook.exe");
    except:
        print("Outlook didn't open successfully")     
#

# Checking if outlook is already opened. If not, open Outlook.exe and send email
for item in psutil.pids():
    p = psutil.Process(item)
    if p.name() == "OUTLOOK.EXE":
        flag = 1
        break
    else:
        flag = 0

if (flag == 1):
    send_notification()
else:
    open_outlook()
    send_notification()
clemens
  • 16,716
  • 11
  • 50
  • 65
Buni_Buni
  • 21
  • 3
1

Other than win32, if your company had set up you web outlook, you can also try PYTHON REST API, which is officially made by Microsoft. (https://msdn.microsoft.com/en-us/office/office365/api/mail-rest-operations)

LinconFive
  • 1,718
  • 1
  • 19
  • 24
-1
import pythoncom
import win32com.client

mail = win32com.client.Dispatch('outlook. Application', 
       pythoncom.CoInitialize())
ol_mail_item = 0x0
new_mail = mail.CreateItem(ol_mail_item)