2

I am new to Python and have recently tried out two approaches to automating the sending out of an email on Outlook 365, one with greater success than the other. I'd like to ask what the key differences are since they look quite vastly different.

The first method is that essentially outlined in the Automate the Boring Stuff book, using SMTP or IMAP. I tried this, but didn't get it to work perhaps because of authentication issues using an office computer.

The second method, which has worked for me, doesn't involve authentication, and I simply import the win32com client and the following code:

outlook = client.Dispatch('Outlook.Application')
message = outlook.CreateItem(0)
message.Display() 
message.To = "redacted"
message.CC = "redacted"
message.Subject = "Hello"

I'd like to ask what are the main ways in which the two methods differ. It seems that the second might rely on Outlook being open and me being logged on, but would the first also work if my computer were put on sleep?

Why go through the first approach which involves authentication when I'm already logged on to Windows and have access to Outlook without needing to enter my user id and password?

I think this is a question that might be useful to others new to Python and email automation, as they may also encounter the two approaches in their search for solutions.

ktan
  • 129
  • 1
  • 9

1 Answers1

5

tldr; if you need to send mail from different mailboxes, use smtplib. If you are automating stuff that you can do manually using outlook, use win32com.client.

SMTP

Referencing the official python docs for SMTP, the methods described there simply allow you to send a mail. (yes, that's it. You cannot even look at the inbox. You'll need imaplib or poplib.)

To me the advantage of smtp is that you can send emails from another person's mailbox if you have his/her credentials. If you were to use win32com.client, you will need to sign out of your own outlook, sign in to that specific person's outlook, then run the code. And for me, I faced the issue where I had to wait for his/her inbox to finish loading before anything gets sent. This is not feasible if you only need to send mail (and not interested in any other functionality such as read or delete mail) from many mailboxes.

[Update] I've recently used smtplib and email (a python builtin package) in a personal project. As it is a personal project, I didn't want to use my office email, hence I decided to use smtplib instead. While there is a need to setup an initial connection, it is very straightforward. Since there is no way to save the email as a draft before sending, the logical workaround is to send it to your own email addresses (or any other 'safe' emails) to test if it works as intended.

import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg['From'] = 'YOUR_EMAIL@GMAIL.COM'
msg['Subject'] = 'Some subject here'
msg['To'] = ', '.join(['adam@gmail.com','bob@gmail.com','candice@gmail.com'])
        
msg.set_content('Some text here')

with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
    smtp.login('YOUR_EMAIL@GMAIL.COM', 'PASSWORD123')
    smtp.send_message(msg)
    print('Email sent!')

win32com.client (focusing on the Outlook application)

You should use this library if you want to automate what you can do on outlook mailboxes that you have access to. Syntax tends to be simpler and it allows you to do stuff that is not possible using only smtplib.

Here are 2 examples to illustrate my point.

Example 1: Automate sending of a calendar invite.

If you were to do it using SMTP, you'll require more code and another library email, specifically .MIMEMultipart, .MIMEBase, .MIMEText, .Utils. The syntax looks intimidating, to say the least. Just take a look at the ical variable of the following stackoverflow answer:

ical = "BEGIN:VCALENDAR"+CRLF+"PRODID:pyICSParser"+CRLF+"VERSION:2.0"+CRLF+"CALSCALE:GREGORIAN"+CRLF
ical+="METHOD:REQUEST"+CRLF+"BEGIN:VEVENT"+CRLF+"DTSTART:"+dtstart+CRLF+"DTEND:"+dtend+CRLF+"DTSTAMP:"+dtstamp+CRLF+organizer+CRLF
ical+= "UID:FIXMEUID"+dtstamp+CRLF
ical+= attendee+"CREATED:"+dtstamp+CRLF+description+"LAST-MODIFIED:"+dtstamp+CRLF+"LOCATION:"+CRLF+"SEQUENCE:0"+CRLF+"STATUS:CONFIRMED"+CRLF
ical+= "SUMMARY:test "+ddtstart.strftime("%Y%m%d @ %H:%M")+CRLF+"TRANSP:OPAQUE"+CRLF+"END:VEVENT"+CRLF+"END:VCALENDAR"+CRLF

win32com.client is so much easier (phew~). There are code examples all over the internet (here and here), and here's a simple example:

ol = w32.Dispatch('Outlook.Application')
appt = ol.CreateItem(1)
appt.Start = '2021-02-06 15:00'
appt.Save()

Example 2: Saving an email as a draft

I often end up automating work for colleagues and when you are sending emails as a batch, it is highly recommended to test by saving the created mail items as a draft. win32com.client allows you to save the mail item as a draft (i.e. .Save()) but smtplib doesn't allow you to do that (reiterate, it only allows you to send a mail.)

[Disclaimer] I done some automation work on outlook and I've always used win32com.client and I have only recently started to use smtplib for a personal project. This question intrigued me and I decided that it is time to at least read a bit more about smtplib.

Ji Wei
  • 840
  • 9
  • 19