Sending Advanced Emails Made Simple in Python

I will give two simple examples that would answer 90% of the questions asked on stackoverflow w.r.t. “python send email” **. Most of the time people are struggling with just simply sending ANY email (using smtplib). And then there are 3 other cases which come up often: sending (rich) HTML, sending attachments, and using some kind of templating.

I will show how easy it can be to send very nice emails using yagmail, without requiring knowledge of SMTP, MIME, manually adding headers and other email specifics. If you don’t know what they all mean: I hope to keep it that way.

Setup

First yagmail should be installed; use pip install yagmail[all] to get your copy. It has been confirmed to work for Python versions 2.7+.

Next, it is possible to save username/password in the keyring locally (and safely), avoiding the need to write username/password in a script. See further instructions here. If you do not want to set it up for now, you can initiate yagmail like yagmail.SMTP("username", "password") in all occurences below instead of yagmail.SMTP().

Now onto some code examples.

Simple email

import yagmail

# create server object; can be reused
yag = yagmail.SMTP()

# use yag.send to actually send messages
yag.send()

Note that all parameters have sensible default values. yag.send() is equal to using yag.send(to='same as "FROM" address', subject="", contents=""). Note the explicit lack of a “from” address: this is set while creating the SMTP object.

Off topic: it is a fun fact that you could technically fake sending-as-someone-else (called “spoofing”) using your own email login info, while it seems the email comes from someone else. Many email providers do not allow this though in these days, so the message may never reach the target or have an exclamation point next to the address. You would possible be marked a spammer as well.

Back on topic: this is why in yagmail you do not provide the from address while sending (though technically you can still do it, but that’s out of scope).

HTML and attachments

Have a look at the code below:

import yagmail
import os

yag = yagmail.SMTP()

csv_file_names = [x for x in os.listdir(".") if x.endswith(".csv")]
contents = "<h1>An HTML Title</h1> Please find files attached"
yag.send("my@friend.com", "The subject", contents, attachments=csv_file_names)

That code will send:

  • an HTML email (with a big title) and some text
  • attached all the files in the current working directory ending with .csv

Furthermore, it can be seen that it is very easy to combine several types of contents, and we do not have to manually play around with any headers. Headers of any kind have been abstracted away!

All of this would be very difficult to accomplish as someone new to sending emails. It is actually quite sad to see many 50-100 lines scripts online for sending emails, written by people not familiar with a layer on top of the standard smtplib.

Don’t forget: we’re writing Python, not Java.

(Marketing) Templating example

Sending to multiple users tailored emails is where it gets interesting though!

Goal: add two inline images uploaded from the current directory, and plug in variables.

The contents of a file email_template.txt looks like:

Dear {name},

I noticed your profile at {social_network}, and it's amazing etc. (standard recruitment).

Take care,
Me

An accompanying python script could look like:

import yagmail

with open("email_template.txt") as f:
    email_template = f.read()

template_data = [
    ("test1@gmail.com", "G. Hub", "GitHub"),
    ("test2@gmail.com", "L. Inkedin", "LinkedIn"),
    ("test3@gmail.com", "R. Editor", "Reddit")
]

yag = yagmail.SMTP()
for to_email, name, social_network in template_data:
    txt = email_template.format(name=name, social_network=social_network)
    # contents, attachments, to, cc, bcc -- all can be a list (plural) or a string (singular)
    contents = [txt, 'brand1.png', 'logo2.png']
    yag.send(to_email, "Hi!", contents)

In case your imagination fails you, the result would look something like this:

Dear G. Hub,

I noticed your profile at GitHub, and it's amazing etc. (standard recruitment).

Take care,
Me

I’ll leave it “as an excercise to the reader” to combine everything into one email: it should not cost many more lines, and by now it should not be difficult.

For all functionality, have a look at the github page. Most questions should be answered there, and you’ll find some other tricks.

Feedback / easter egg

Please, feel free to leave a comment or send me feedback through email directly using:

with yagmail.SMTP() as yag:
    yag.feedback("Awesome features! You made my day! How can I contribute?")

Bonus: note the context manager with; it will close the SMTP object after use.

Contributions

See here for the wonderful contributions made by others!

Open issue: Looking for contributor who could add OAuth2 to yagmail

Related, there are 2 packages using yagmail currently:

And here you can see what other people on GitHub did with it so far.


** Note that you can actually track tags on StackOverflow using IfThisThenThat.