Email

Sending Emails

Simple Mail Transfer Protocol (SMTP) is a protocol used to send email

To import smtplib

In [1]:
import smtplib

To connect to SMTP server of your provider

In [2]:
conn = smtplib.SMTP('smtp.gmail.com', 587)
type(conn)
Out[2]:
smtplib.SMTP
In [3]:
conn
Out[3]:
<smtplib.SMTP at 0x4a0d4f0>

Next, call ehlo()

In [4]:
conn.ehlo()
Out[4]:
(250,
 b'smtp.gmail.com at your service, [219.78.190.90]\nSIZE 35882577\n8BITMIME\nSTARTTLS\nENHANCEDSTATUSCODES\nPIPELINING\nSMTPUTF8')

Call starttls() to start TLS encryption

In [5]:
conn.starttls()
Out[5]:
(220, b'2.0.0 Ready to start TLS')

Call login() with your username and password

In [6]:
conn.login('vrunrun@gmail.com','egliztzoghkrtbvw')
Out[6]:
(235, b'2.7.0 Accepted')

Call sendmail() with the "from", "to" email addresses, the subject line followed by the message body. The returned object contains email address that are failed to send.

In [7]:
conn.sendmail('vrunrun@gmail.com', 'vrunrun@gmail.com', 'Subject: So long...\n\nDear X,\nSo long, and thanks for all the fish\n\n-XX')
Out[7]:
{}

Call quit() to close the connection

In [8]:
conn.quit()
Out[8]:
(221, b'2.0.0 closing connection w63sm30990997pgb.80 - gsmtp')

The returned tuple from conn.ehlo(), conn.starttls(), conn.login() consists of a digit and a string of bytes data type. For the digit, anything starts with 2 means OK. All bytes data begin with a "b"

Email Providers and Their SMTP Servers

Provider SMTP server domain name
Gmail smtp.gmail.com
Outlook.com/Hotmail.com smtp-mail.outlook.com
Yahoo Mail smtp.mail.yahoo.com
AT&T smtp.mail.att.net (port 465)
Comcast smtp.comcast.net
Verizon smtp.verizon.net (port 465)

Google Sign in using App Passwords

Google has something called app specific password that gives an app permission to access your Google Account. You should pass app specific password to conn.login() method instead of password for normal google account

Email providers impose limit on number of emails send per day

Checking Your Email Inbox

The Internet Message Access Protocol (IMAP) specifies how to communicate with email server to retrieve emails.

In [9]:
# pip install imapclient
# pip install pyzmail36 (for Python 3.6.x)
# pip install pyzmail (for older Python version)
In [10]:
import imapclient
In [11]:
conn = imapclient.IMAPClient('imap.gmail.com', ssl=True)
In [12]:
conn.login('vrunrun@gmail.com','egliztzoghkrtbvw')
Out[12]:
b'vrunrun@gmail.com authenticated (Success)'
In [13]:
conn.select_folder('INBOX', readonly=True)
Out[13]:
{b'EXISTS': 1454,
 b'FLAGS': (b'\\Answered',
  b'\\Flagged',
  b'\\Draft',
  b'\\Deleted',
  b'\\Seen',
  b'$Forwarded',
  b'$NotPhishing',
  b'$Phishing'),
 b'HIGHESTMODSEQ': 562423,
 b'PERMANENTFLAGS': (),
 b'READ-ONLY': [b''],
 b'RECENT': 0,
 b'UIDNEXT': 2876,
 b'UIDVALIDITY': 5}
In [14]:
UIDs = conn.search('(SINCE "6-Mar-2018")')
UIDs
Out[14]:
[2873, 2874, 2875]
In [15]:
rawMessage = conn.fetch([2873], ['BODY[]', 'FLAGS'])
In [16]:
import pyzmail
In [17]:
pyzmail.PyzMessage.factory(rawMessage[2873][b'BODY[]'])
Out[17]:
<pyzmail.parse.PyzMessage at 0x4b192d0>
In [18]:
message = pyzmail.PyzMessage.factory(rawMessage[2873][b'BODY[]'])
In [19]:
message.get_subject()
Out[19]:
'So long...'
In [20]:
message.get_addresses('from')
Out[20]:
[('vrunrun@gmail.com', 'vrunrun@gmail.com')]
In [21]:
message.get_addresses('bcc')
Out[21]:
[('vrunrun@gmail.com', 'vrunrun@gmail.com')]
In [22]:
message.text_part
Out[22]:
MailPart<*text/plain len=166>
In [23]:
message.text_part == None
Out[23]:
False
In [24]:
message.text_part.get_payload().decode('UTF-8')
Out[24]:
'Dear X,\r\nSo long, and thanks for all the fish\r\n\r\n-XX\r\n\r\n---\r\nThis email has been checked for viruses by Avast antivirus software.\r\nhttps://www.avast.com/antivirus\r\n\r\n'
In [25]:
message.text_part.charset == None
Out[25]:
True
In [26]:
conn.list_folders()
Out[26]:
[((b'\\HasNoChildren',), b'/', 'Call'),
 ((b'\\HasNoChildren',), b'/', 'Deleted Messages'),
 ((b'\\HasNoChildren',), b'/', 'Drafts'),
 ((b'\\HasNoChildren',), b'/', 'INBOX'),
 ((b'\\HasNoChildren',), b'/', 'Junkbox'),
 ((b'\\HasNoChildren',), b'/', 'Message'),
 ((b'\\HasNoChildren',), b'/', 'Notes'),
 ((b'\\HasNoChildren',), b'/', 'Outbox'),
 ((b'\\HasNoChildren',), b'/', 'Sent Messages'),
 ((b'\\HasChildren', b'\\Noselect'), b'/', '[Gmail]'),
 ((b'\\All', b'\\HasNoChildren'), b'/', '[Gmail]/All Mail'),
 ((b'\\Drafts', b'\\HasNoChildren'), b'/', '[Gmail]/Drafts'),
 ((b'\\HasNoChildren', b'\\Important'), b'/', '[Gmail]/Important'),
 ((b'\\HasNoChildren', b'\\Sent'), b'/', '[Gmail]/Sent Mail'),
 ((b'\\HasNoChildren', b'\\Junk'), b'/', '[Gmail]/Spam'),
 ((b'\\Flagged', b'\\HasNoChildren'), b'/', '[Gmail]/Starred'),
 ((b'\\HasNoChildren', b'\\Trash'), b'/', '[Gmail]/Trash'),
 ((b'\\HasChildren',), b'/', '[Mailbox]'),
 ((b'\\HasNoChildren',), b'/', '[Mailbox]/Later'),
 ((b'\\HasNoChildren',), b'/', '[Mailbox]/To Buy'),
 ((b'\\HasNoChildren',), b'/', '[Mailbox]/To Read'),
 ((b'\\HasNoChildren',), b'/', '[Mailbox]/To Watch')]

Delete emails

In [27]:
conn.select_folder('INBOX', readonly=False)
UIDs = conn.search('(ON "7-Mar-2018")')
UIDs
Out[27]:
[2873, 2874, 2875]
In [28]:
# conn.delete_messages([2867])
# conn.delete_messages(UIDs)
In [29]:
conn.logout()
Out[29]:
b'LOGOUT Requested'

Email Providers and Their IMAP Servers

Provider IMAP server domain name
Gmail imap.gmail.com
Outlook.com/Hotmail.com imap-mail.outlook.com
Yahoo Mail imap.mail.yahoo.com
AT&T imap.mail.att.net
Comcast imap.comcast.net
Verizon imap.verizon.net

IMAP Search Keys

Refer to table 16-3 of the <a href = "https://automatetheboringstuff.com/chapter16/" target="_blank">"Automate the Boring Stuff with Python"</a> book

See the IMAP cheat sheet in the course notes for an overview of the entire process

More documentation at: https://imapclient.readthedocs.org http://www.magiksys.net/pyzmail