How to send beautiful emails with attachments (yes, cat pics too) using only Python
Tags: python, tutorial, learning
Published: 2019-09-25 05:32:00


Original post: [https://letslearnabout.net/tutorial/how-to-send-beautiful-emails-with-attachments-using-only-python/](https://letslearnabout.net/tutorial/how-to-send-beautiful-emails-with-attachments-using-only-python/?preview=true&_thumbnail_id=1485 "Permalink to How to send beautiful emails with attachments (yes, cat pics too) using only Python")

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

![Send emails using Python header][1]

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][2]

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

{% youtube m9ojKEBYCvQ %}

* * *

### 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][3]

![Less secure access][4]

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_):

![][5]

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?
    '''


_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()

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][5]

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][6]

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

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

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())

Send the email again:

![][7]

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]

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')
        ...
    
    

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()
    

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()

Replace the old line with the new one:
    
    
    # msg = MIMEText(email_body, 'plain') # Old line
    msg = MIMEText(email_body, 'html') # New line

Run the code and this is the result:

![Send emails using Python][8]

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
    

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'))

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}')
    

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()
    

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

![Send emails using Python][9]

* * *

### 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][10]

[Final code on Github][11]

[Reach to me on Twitter][12]

[Read more tutorials][13]

[1]: https://i1.wp.com/letslearnabout.net/wp-content/uploads/2019/09/image-30.png?fit=688%2C325&ssl=1
[2]: https://i0.wp.com/letslearnabout.net/wp-content/uploads/2019/09/image-36.png?w=688&ssl=1
[3]: https://myaccount.google.com/u/0/security?hl=en&pli=1
[4]: https://i2.wp.com/humberto.io/img/emails/less-secure.png?w=688&ssl=1
[5]: https://i2.wp.com/letslearnabout.net/wp-content/uploads/2019/09/image-32.png?w=688&ssl=1
[6]: https://i0.wp.com/letslearnabout.net/wp-content/uploads/2019/09/image-33.png?w=688&ssl=1
[7]: https://i0.wp.com/letslearnabout.net/wp-content/uploads/2019/09/image-34.png?w=688&ssl=1
[8]: https://i2.wp.com/letslearnabout.net/wp-content/uploads/2019/09/image-35.png?w=688&ssl=1
[9]: https://i0.wp.com/letslearnabout.net/wp-content/uploads/2019/09/image-37.png?w=688&ssl=1
[10]: https://www.youtube.com/channel/UC9OLm6YFRzr4yjlw4xNWYvg?sub_confirmation=1
[11]: https://github.com/david1707/automated_emails
[12]: https://twitter.com/DavidMM1707
[13]: https://letslearnabout.net/category/tutorial/