DEV Community

Cover image for How to send beautiful emails with attachments (yes, cat pics too) using only Python
David MMπŸ‘¨πŸ»β€πŸ’»
David MMπŸ‘¨πŸ»β€πŸ’»

Posted on • Edited on

How to send beautiful emails with attachments (yes, cat pics too) using only Python

Original post: https://letslearnabout.net/tutorial/how-to-send-beautiful-emails-with-attachments-using-only-python/

How to send beautiful emails with attachments (yes, cat pics too) using only Python

Send emails using Python header

Did you know you can send emails using Python? Not only that, you can send files attached too!

And instead of using the black-text-white-background plain text most people use, you can send your emails as HTML files, to add some flavour to your emails, like this one:

Send emails using Python final email

In just a few minutes, you will learn how to create an SMTP server to send emails using Python to a list of clients, students, friends…

In this video you'll learn how to:

  • Send one email to one person
  • Add information such as your name, the receiver name or a subject to make it more human-like
  • Send one email to multiple people
  • Make a beautiful email using HTML
  • Attach files to the emails we sent


Setting up everything

We are going to send emails using a Gmail account. Before anything, create a gmail account (or use your own) and enable the "Less secure app access" in your account. You can do it here: https://myaccount.google.com/u/0/security?hl=en&pli=1

Less secure access

After that, you are set! Create an environment with Python (I use pipenv, so _pipenv shell) _and you are ready to go!


Simple, one to one email sender

Let's start by creating a simple script that sends one text email to other people from your account (I use pipenv, so I create one with pipenv_ shell_):

Create a python file, for example email_server.py, and write:

import smtplib, ssl


# User configuration
sender_email = YOUR_EMAIL
receiver_email = RECEIVER_EMAIL
password = input('Please, type your password:n')

# Email text
email_body = '''
    This is a test email sent by Python. Isn't that cool?
'''
Enter fullscreen mode Exit fullscreen mode

smtp is a Python module we will use to create an SMTP (Simple Mail Transfer Protocol) session object that will send any email we want. ssl module provides access to TLS (Transport Layer Security) to help us making it more secure.

Then, we'll add some variables such as the sender and receiver email, a prompt to the user to enter the email password and a body to the email. Replace the values in uppercase with yours. For testing purposes, I use the same email.

After having our configuration, let's write the function that will send the emails:

print("Sending the email...")
try:
        # Creating a SMTP session | use 587 with TLS, 465 SSL and 25
        server = smtplib.SMTP('smtp.gmail.com', 587)
        # Encrypts the email
        context = ssl.create_default_context()
        server.starttls(context=context)
        # We log in into our Google account
        server.login(sender_email, password)
        # Sending email from sender, to receiver with the email body
        server.sendmail(sender_email, receiver_email, email_body)
        print('Email sent!')
except Exception as e:
        print(f'Oh no! Something bad happened!n {e}')
finally:
        print('Closing the server...')
        server.quit()
Enter fullscreen mode Exit fullscreen mode

This function will:

  • Create a smtplib.SMTP instance. We use gmail so we send it using the host smtp.gmail.com and the port 587. You can use other providers (such as hotmail) by using their host and port.
  • Encrypt the email using the _starttl_s method.
  • Log into our Google email account
  • Send the email using the sender email, to the receiver email, and the message is just a plain text.
  • Use a try, except to catch all the errors and _finallyi_close the SMTP instance.

Run the code now and you'll receive your email!

This image has an empty alt attribute; its file name is image-32.png

But we are not here to send just an email. We can do that ourselves!

Let's send now multiple emails to a list.


Sending emails to a list of people

To send multiple emails, we only need to perform a few tweaks here and there. Let's also make our emails more personal adding a subject to the email and information about the sender:

Send emails using Python personalized

First, let's write more human-like emails:

import smtplib, ssl
from email.mime.text import MIMEText # New line
from email.utils import formataddr  # New line


# User configuration
sender_email = YOUR_EMAIL
sender_name = YOUR NAME  # New line
password = input('Please, type your password:n')    

receiver_email = RECEIVER_EMAIL
receiver_name = RECEIVER_NAME  # New line
Enter fullscreen mode Exit fullscreen mode

Add the lines with the '# New line' comment. We are importing the MIMEText( Multi-Purpose Internet Mail Extensions ) to configure our emails and a _formataddr_helper method.

After the first print but before the try, add this configuration:

# Configurating user's info
msg = MIMEText(email_body, 'plain')
msg['To'] = formataddr((receiver_name, receiver_email))
msg['From'] = formataddr((sender_name, sender_email))
msg['Subject'] = 'Hello, my friend ' + receiver_name
Enter fullscreen mode Exit fullscreen mode

Now, we create a MIMEText instance with email_body as plain text, we set our 'To' text to the receiver name and email, the 'From' text to our name and email and the subject to 'Hello, my friend NAME'.

Finally, modify the sender.sendmail method to:

server.sendmail(sender_email, receiver_email, msg.as_string())
Enter fullscreen mode Exit fullscreen mode

Send the email again:

Nice, now has less spammy vibes. Let's send that 100% normal, not-fake, email to a list of people:

# receiver_email = RECEIVER_EMAIL
# receiver_name = RECEIVER_NAME

receiver_emails = [RECEIVER_EMAIL_1, RECEIVER_EMAIL_2, RECEIVER_EMAIL_3]
receiver_names = [RECEIVER_NAME_1, RECEIVER_NAME_2, RECEIVER_NAME_3]
Enter fullscreen mode Exit fullscreen mode

As we are going to iterate over the receiver emails and names, precede the code bellow the _receiver_names _variable with this for-loop and tab the code so it belongs to the loop:

for receiver_email, receiver_name in zip(receiver_emails, receiver_names):
    print("Sending the email...")
    # Configurating user's info
    msg = MIMEText(email_body, 'plain')
    ...
Enter fullscreen mode Exit fullscreen mode

This should be your code right now:

import smtplib
import ssl
from email.mime.text import MIMEText  # New line
from email.utils import formataddr  # New line

# User configuration
sender_email = YOUR_EMAIL
sender_name = YOUR NAME
password = input('Please, type your password:n')

receiver_emails = [RECEIVER_EMAIL_1, RECEIVER_EMAIL_2, RECEIVER_EMAIL_3]
receiver_names = [RECEIVER_NAME_1, RECEIVER_NAME_2, RECEIVER_NAME_3]

# Email text
email_body = '''
    This is a test email sent by Python. Isn't that cool?
'''

for receiver_email, receiver_name in zip(receiver_emails, receiver_names):
    print("Sending the email...")
    # Configurating user's info
    msg = MIMEText(email_body, 'plain')
    msg['To'] = formataddr((receiver_name, receiver_email))
    msg['From'] = formataddr((sender_name, sender_email))
    msg['Subject'] = 'Hello, my friend ' + receiver_name
    try:
        # Creating a SMTP session | use 587 with TLS, 465 SSL and 25
        server = smtplib.SMTP('smtp.gmail.com', 587)
        # Encrypts the email
        context = ssl.create_default_context()
        server.starttls(context=context)
        # We log in into our Google account
        server.login(sender_email, password)
        # Sending email from sender, to receiver with the email body
        server.sendmail(sender_email, receiver_email, msg.as_string())
        print('Email sent!')
    except Exception as e:
        print(f'Oh no! Something bad happened!n {e}')
    finally:
        print('Closing the server...')
        server.quit()
Enter fullscreen mode Exit fullscreen mode

Run the code and your email will be send to 3 different email address!

Here we are sending an email to 3 different people, but you can send it to hundreds of your students, followers, blog readers, etc! And…

…they will get an ugly email.

I promised you sending beautiful emails with Python that can draw people to whatever you want. So let's go!


Sending beautiful emails with HTML

It's pretty simple. Now we are sending a string as a _email_body, _right?

Instead of that, we are going to send a string that contains HTML code.

First, let's create our HTML file. Use a code editor such as VS Code or Atom, or create it with an online editor such as .

Save it into an HTML file (mine is email.html).

Now, place email_body with this:

# Email body
email_html = open('email.html')
email_body = email_html.read()
Enter fullscreen mode Exit fullscreen mode

Replace the old line with the new one:

# msg = MIMEText(email_body, 'plain') # Old line
msg = MIMEText(email_body, 'html') # New line
Enter fullscreen mode Exit fullscreen mode

Run the code and this is the result:

Send emails using Python

Pretty cool, right?

But what if we want to send also invoices, pdfs, excel files, videos, or some other file?


Add files to your emails – The mandatory cat.gif example

To add files, instead of sending one object, the HTML, we are going to send multiple parts. One being the HTML, other the gif. To do so, add this:

import smtplib, ssl
from email.mime.text import MIMEText
from email.utils import formataddr
from email.mime.multipart import MIMEMultipart # New line
from email.mime.base import MIMEBase # New line
from email import encoders # New line

....
# Email body
email_html = open('email.html')
email_body = email_html.read()

filename = 'cat.gif' # New line
Enter fullscreen mode Exit fullscreen mode

Remember to add a file called 'cat.gif' to the folder or replace it with one of your own.

Replace the _msg = MIMEText(email_body, 'html') _creation with this:

    msg = MIMEMultipart()
    msg['To'] = formataddr((receiver_name, receiver_email))
    msg['From'] = formataddr((sender_name, sender_email))
    msg['Subject'] = 'Hello, my friend ' + receiver_name

   msg.attach(MIMEText(email_body, 'html'))
Enter fullscreen mode Exit fullscreen mode

This will create the first part of the body, the one with the HTML, now let's add the attachment:

try:
            # Open PDF file in binary mode
            with open(filename, "rb") as attachment:
                            part = MIMEBase("application", "octet-stream")
                            part.set_payload(attachment.read())

            # Encode file in ASCII characters to send by email
            encoders.encode_base64(part)

            # Add header as key/value pair to attachment part
            part.add_header(
                    "Content-Disposition",
                    f"attachment; filename= {filename}",
            )

            msg.attach(part)
        except Exception as e:
                print(f'Oh no! We didn't found the attachment!n{e}')
Enter fullscreen mode Exit fullscreen mode

This will:

  • Load the file attached
  • Encode it
  • Add it to the header as attachment
  • Add the part to the MIMEMultipart
  • Throw and error if the file isn't found.

Check your code with mine:

import smtplib
import ssl
from email.mime.text import MIMEText
from email.utils import formataddr
from email.mime.multipart import MIMEMultipart  # New line
from email.mime.base import MIMEBase  # New line
from email import encoders  # New line

# User configuration
sender_email = YOUR_EMAIL
sender_name = YOUR_NAME
password = input('Please, type your password:n')

receiver_emails = [RECEIVER_EMAIL_1, RECEIVER_EMAIL_2, RECEIVER_EMAIL_3]
receiver_names = [RECEIVER_NAME_1, RECEIVER_NAME_2, RECEIVER_NAME_3]

# Email body
email_html = open('email.html')
email_body = email_html.read()

filename = 'cat.gif'

for receiver_email, receiver_name in zip(receiver_emails, receiver_names):
        print("Sending the email...")
        # Configurating user's info
        msg = MIMEMultipart()
        msg['To'] = formataddr((receiver_name, receiver_email))
        msg['From'] = formataddr((sender_name, sender_email))
        msg['Subject'] = 'Hello, my friend ' + receiver_name

        msg.attach(MIMEText(email_body, 'html'))

        try:
            # Open PDF file in binary mode
            with open(filename, "rb") as attachment:
                            part = MIMEBase("application", "octet-stream")
                            part.set_payload(attachment.read())

            # Encode file in ASCII characters to send by email
            encoders.encode_base64(part)

            # Add header as key/value pair to attachment part
            part.add_header(
                    "Content-Disposition",
                    f"attachment; filename= {filename}",
            )

            msg.attach(part)
        except Exception as e:
                print(f'Oh no! We didn't found the attachment!n{e}')
                break

        try:
                # Creating a SMTP session | use 587 with TLS, 465 SSL and 25
                server = smtplib.SMTP('smtp.gmail.com', 587)
                # Encrypts the email
                context = ssl.create_default_context()
                server.starttls(context=context)
                # We log in into our Google account
                server.login(sender_email, password)
                # Sending email from sender, to receiver with the email body
                server.sendmail(sender_email, receiver_email, msg.as_string())
                print('Email sent!')
        except Exception as e:
                print(f'Oh no! Something bad happened!n{e}')
                break
        finally:
                print('Closing the server...')
                server.quit()
Enter fullscreen mode Exit fullscreen mode

Run the code… and now the attachment is in the email!

Send emails using Python


Conclusion

Writing code that lets you send an email to your email list, with attachment files and way more attractive than the boring plain black-text-white-background formula, is easy.

While this is a one-file script, you can easily incorporate it to an actual Python framework (Flask, Django….) web app, another program you are actually using or improve the current one to perform more functions.

Creating and sending emails never has been so easy with Python!


My Youtube tutorial videos

Final code on Github

Reach to me on Twitter

Read more tutorials

Top comments (4)

Collapse
 
mahesh14694628 profile image
Mahesh

How can we send an Emoji with text using SMTPLIB? , the below is the test im trying to send
TLA:⬆-8% ,Tlanc. stock rises Thursday, outperforms market

But, this is the Email im getting, please help me out
b'TLA:\xe2\xac\x87-8% ,Tlanc. stock rises Thursday, outperforms market'

Collapse
 
devpbrilius profile image
Povilas Brilius

beauty and aesthetics are associated somehow with python exceptionally, php left aside like it was the bad guy in e-commerce.

Collapse
 
davidmm1707 profile image
David MMπŸ‘¨πŸ»β€πŸ’»

The "beauty" achieved sending emails with Python comes from using HTML tags, and it can be done too with PHP, so it's no Python-exclusive :)

Collapse
 
theworldoftheweb profile image
Michael Hyland

Thanks for this. It was essential to a project I was building for work.