Arjun Krishna Babu bio photo

Arjun Krishna Babu

Python. Machine Learning. Systems. Open source.

Email LinkedIn Github

Figuring out how to send emails using code is something that has been in my to-do list for sometime. And well, it has finally made it to the top of the stack, and here I am tackling the issue.

Turns out, sending emails using code is pretty easy and straightforward. Yay!

Please do note upfront that this was more of a learning exercise for me to learn how to fire off a bunch of emails to a bunch of people; there might probably be more straightforward methods to do the same thing in a production environment.

The language I chose is Python (python3 to be specific), as I prefer its simplicity. It is one of those languages that I’m more or less used to, and I was pretty certain there would be straightforward libraries for implementing the email functionality in Python.

As an aside, I had tried implementing something similar using PHP a couple of years ago, and that did not go very well.

So, here’s a scenario. You’ve got a bunch of contacts — names and email addresses of people. And you wish to send a message to each one of those contacts, while adding a “Dear XYZ” to the top of the message.

It’s not a very rare requirement or something. Perhaps you need to send a welcome email when somebody signs up on a website. Or something similar.

So, let’s start cranking!

For simplicity’s sake I’m storing the contact details in a file rather than a database in this example. Along with that, the template of the message you wish to send is also stored in a file.

The smtplib module of Python is handy for sending emails, and is basically all that you require for sending simple emails, without any subject line or such additional information. However, in real emails, you do need the subject line and all the other information (perhaps even pictures and attachments and whatnot!).

This is where the email package in Python comes in. Do keep in mind that it is not possible to send an email message using the email package alone; you need a combination of both email and smtplib.

The official documentation for both of these are very comprehensive. Please do check it out.

There are four basic steps to sending emails using Python:

  1. Set up the SMTP server and log in to our account.
  2. Create the MIMEMultipart message object and load it with appropriate headers for From, To, and Subject fields.
  3. Add in the message body.
  4. Send the message using the SMTP server object.

Let me walk you through the whole process.

Let’s say I have a contacts file mycontacts.txt as follows:

user@computer ~ $ cat mycontacts.txt
john johndoe@example.com
katie katie2016@example.com

Each line represents a single contact. We have the name followed by the email address. I’m storing everything in lowercase; I’ll leave it to the programming logic to convert any fields to upper-case or sentence-case if necessary. All of that is pretty easy in Python.

Next, we have the message template file message.txt.

user@computer ~ $ cat message.txt
Dear ${PERSON_NAME},

This is a test message.
Have a great weekend!

Yours Truly

Notice the word ${PERSON_NAME}? That is a Template string in Python. Template strings can easily be replaced with other strings; in this example, ${PERSON_NAME} is going to be replaced with the actual name of the person, as you’ll see shortly.

Now let’s start with the Python code. First up, we need to read the contacts from the mycontacts.txt file. We might as well generalize this bit into its own function.

1
2
3
4
5
6
7
8
9
10
# Function to read the contacts from a given contact file and return a
# list of names and email addresses
def get_contacts(filename):
    names = []
    emails = []
    with open(filename, mode='r', encoding='utf-8') as contacts_file:
        for a_contact in contacts_file:
            names.append(a_contact.split()[0])
            emails.append(a_contact.split()[1])
    return names, emails

The function get_contacts() takes a filename as its argument. It will open the file, read a line (ie., a contact), split it into name and email, and then append them into two separate lists. Finally, the two lists are returned from the function.

We also need a function to read in a template file (like message.txt) and return a Template object made from its contents.

1
2
3
4
5
6
from string import Template

def read_template(filename):
    with open(filename, 'r', encoding='utf-8') as template_file:
        template_file_content = template_file.read()
    return Template(template_file_content)

In case you wish to brush up your memories on templates in Python, the official docs on Template strings would be a useful resource.

To send the email, you need to make use of SMTP (Simple Mail Transfer Protocol). As mentioned earlier, Python provides libraries to handle this task.

1
2
3
4
5
6
7
# import the smtplib module. It should be included in Python by default
import smtplib

# set up the SMTP server
s = smtplib.SMTP(host='your_host_address_here', port=your_port_here)
s.starttls()
s.login(MY_ADDRESS, PASSWORD)

In the above code snippet, you’re importing the smtplib and then creating an SMTP instance that encapsulates an SMTP connection. It takes as parameter the host address and a port number, both of which entirely depends on the SMPT settings of your particular email service provider. For instance, in the case of Outlook, line 5 above would have been

s = smtplib.SMTP(host='smtp-mail.outlook.com', port=587)

You should use the host address and port number of your particular email service provider for the whole thing to work.

MY_ADDRESS and PASSWORD above are two variables that holds the full email address and password of the account you’re going to use.

Now would be a good time to fetch the contact information and the message templates using the functions we defined above.

1
2
names, emails = get_contacts('mycontacts.txt') # read contacts
message_template = read_template('message.txt')

That should be a no-brainer.

Now, for each of those contacts, let’s send the mail separately.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# import necessary packages
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# For each contact, send the email:
for name, email in zip(names, emails):
    msg = MIMEMultipart()       # create a message

    # add in the actual person name to the message template
    message = message_template.substitute(PERSON_NAME=name.title())

    # Prints out the message body for our sake
    print(message)

    # setup the parameters of the message
    msg['From']=MY_ADDRESS
    msg['To']=email
    msg['Subject']="This is TEST"

    # add in the message body
    msg.attach(MIMEText(message, 'plain'))

    # send the message via the server set up earlier.
    s.send_message(msg)
    print("SENT EMAIL TO ", name)
    del msg

For each name and email (from the contacts file), you’re creating a MIMEMultipart object, setting up the From, To, Subject content-type headers as a keyword dictionary, and then attaching the message body to the MIMEMultipart object as plain text. You might want to read the documentation to find out more about other MIME types you can experiment with.

Also note that on line 10 above, I’m replacing ${PERSON_NAME} with the actual name extracted from the contacts file using the templating mechanism in Python.

In this particular example I’m deleting the MIMEMultipart object and re-creating it each time you iterate through the loop. (I do admit I have doubts as to whether that’s the most efficient way of dealing with things; I’ll update on that later.)

Once that is done, you can send the message using the handy send_message() function of the SMTP object you created earlier.

I’m pasting below the full code just in case you wish to see it.

There you go! I believe the code is now fairly clear.

Feel free to copy and tweak it as necessary.

Happy coding :)

P.S: Apart from the official Python docs, I would also like to mention this resource which helped me a lot.