Python

Send Emails using Python (Multiple Examples)

Python lets you automate the task of sending emails by using its built-in modules. Doing so frees you from the tedious and time-consuming task of manually sending emails to thousands of users.

This tutorial will look into some fast, easy ways of sending emails and working with Python’s built-in email modules.

 

 

Check if Email Exists

Often, you may want to check whether an email entered by a user is a valid email or syntactically incorrect. Moreover, you may also want to check whether the email address actually exists. This can be quickly done using Python.

A valid email address has a specific format. There always exists an ‘@’ symbol. The prefix is the part before the @ sign, and the postfix is followed after the @ sign.

The postfix has to be a verified domain name. Email addresses can contain numbers, alphabets, periods, dashes, and underscores.

If a dash or underscore is used, it needs to be followed by an alphabet or a number. These are the rules that define a correct email address.

Python’s re module comes in handy if you want to check the syntax of an email address entered by a user. ‘re’ is a short form for regular expressions.

You can create a regular expression that matches the syntax of a valid email. To do this, you need to understand how regular expressions work. Below is a regular expression that checks the syntax for an email address.

import re
valid_regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
def check(email):
  if(re.fullmatch(valid_regex, email)):
    print("This is a valid email") 
  else:
    print("This is an invalid email")
email = "correctemail@gmail.com"
check(email)

Check email using re

Using the re module requires you to have a solid understanding of the regular expressions.

An even better way to check whether an email exists is to use a third-party package named validate-email-address. You can install this module using a package manager such as pip.

$ pip install py3-validate-email
from validate_email import validate_email
valid_email = validate_email(email_address='example@gmail.com')

Check email using validate_email

The great thing about this package is that it checks the syntax of an email and checks whether the given email address exists by simulating an actual email delivery. To do this, you need to set the check_smtp flag to true.

from validate_email import validate_email
valid_email = validate_email(email_address='example@gmail.com', check_smtp = True)    

Check email using validate_email

 

Python Email server

To send emails using Python, you need to set up an email server first. The most common way and the industry-standard protocol for sending emails is by using the SMTP protocol.

SMTP is an abbreviation for Simple Mail Transfer Protocol. Email service providers make use of SMTP servers and the SMTP protocol to send or relay messages.

You can create your own SMTP email server using the smtplib module of Python. The module lets you send simple messages without a subject line or multimedia.

Python also has an inbuilt email package that allows you to send additional attachments alongside your text message. When used in conjunction with the smtplib module, you can send rich emails with attachments and subject lines.

To create an email server using the smtplib module, you first need to run the import statement.

import smtplib

You can then create an SMTP instance that encapsulates an SMTP connection. You can set up the optional parameters host and port to specify the port and host, depending upon your particular email service provider.

To set up a connection that closes automatically, you need to use the ‘with’ statement.

from smtplib import SMTP
with SMTP(host= "exampledomain.com", port= 587) as smtp:
    smtp.starttls()
    smtp.noop()

Python email server

When you use SMTP, the connection initiated is not secure. This is why you need to encrypt it using starttls().

An alternative is to start a secure connection from the beginning rather than encrypting it after the connection has been initiated. The SMTP_SSL instance is used for this case.

from smtplib import SMTP
server = "smtp-mail.outlook.com"
port = 587
with smtplib.SMTP_SSL(server, port) as server:
    server.login("example@outlook.com", password="StrongPassword")

Python email server with SSL

 

Send Email with Python

Once you have set up your email server, you can relay emails to valid addresses. The sendmail() function does this. It requires you to specify the email address of the sender and receiver, along with the message.

If your SMTP server requires authentication to send a message, you’ll need to enter the credentials of your email account.

You can pass the username and password to the login() function, which will perform the authentication.

When using the smtplib module, there are two ways you could go about sending emails. Both of them ensure that your SMTP connection is secure and encrypted.

 

Sending Emails via SMTP

As seen earlier, you can first initiate a connection that is not encrypted over TLS, and later encrypt it using starttls(). In this case, an instance of the SMTP class is created.

import smtplib
import ssl
port = 587  
smtp_server = "smtp-mail.outlook.com"
sender = "sender@outlook.com"
recipient = "receiver@gmail.com"
sender_password = "strongpassword"
message = """
Subject: This is a test message
Sent using Python."""
SSL_context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
    server.starttls(context=SSL_context)
    server.login(sender, sender_password)
    server.sendmail(sender, recipient, message)

Python email server using SMTP

 

Send with SMTP SSL

The second way to send an email is to initiate a secure connection over TLS. This is the right option in situations where SSL is required from the beginning of the connection.

import smtplib
import ssl
port = 465  
smtp_server = "smtp-mail.outlook.com"
sender = "sender@outlook.com"
recipient = "receiver@gmail.com"
sender_password = "strongpassword"
message = """
Subject: This is a test message
Send using Python."""
SSL_context = ssl.create_default_context()
with smtplib.SMTP_SSL(smtp_server, port, context=SSL_context) as server:
    server.login(sender, sender_password)
    server.sendmail(sender, recipient, message)

Python email server using SMTP and SSL

 

Send Email without SMTP server

If you do not want to set up an SMTP server to send emails, the chilkat module will be your best bet. It contains the Chilkat MailMan class, which is responsible for sending and receiving emails through SMTP and POP3 servers, respectively.

The module provides a method MxLookup that performs a DNS MX lookup to find the mail server using the recipient’s email address. You’ll need to install the chilkat module for doing this.

import sys
import chilkat
mailman = chilkat.CkMailMan()
receiver_address = "example@domain.com"
smtpHost = mailman.mxLookup(receiver_address)
if (mailman.get_LastMethodSuccess() != True):
    print(mailman.lastErrorText())
    sys.exit()
mailman.put_SmtpHost(smtpHost)
mail = chilkat.CkEmail()
mail.put_Subject("A test subject")
mail.put_Body("Hello!")
mail.put_From("")
mail.AddTo("", receiver_address)
success = mailman.SendEmail(mail)
if (success != True):
    print(mailman.lastErrorText())
else:
    print("Sent!")

Python email server without SMTP

 

Email MIME text

If you want to send plain text emails without subjects or emphasis (bolds, italics, or underlines), the smtplib module from Python is enough to get the job done.

However, you often want to add attachments (images, hyperlinks, etc.) or responsive content in real-life scenarios with your plain text. Python’s built-in email module comes in handy in such situations.

MIME, an abbreviation for Multipurpose Internet Mail Extensions, is a type of email that uses HTML combined with plain text.

It extends the SMTP protocol to support images, videos, audio, and other attachments. Python’s email.mime module allows you to include HTML or attachments when sending emails over the SMTP server.

To do that, you need to import the modules by running the following statement.

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
import ssl
port = 587
server = "smtp-mail.outlook.com"
sender = "example@outlook.com"
recipient = "example@gmail.com"
password = "strongpassword"
msg = MIMEMultipart()       
message = """Hi,
This is a MIME text
"""
msg['From']= sender_email
msg['To']= receiver_email
msg['Subject']="This is a text email for MIME"
msg.attach(MIMEText(message, "plain"))
text = msg.as_string()
SSLcontext = ssl.create_default_context()
with smtplib.SMTP(server, port) as server:
    server.starttls(context=SSLcontext)
    server.login(sender, password)
    server.sendmail(sender, recipient, text) 

Python email MIME text

 

Send HTML Email

Besides sending MIME text over an SMTP server, the email.mime also works well for sending HTML emails. The process is exactly the same as above, with a subtle difference in the MIMEText() function.

You passed “plain” as the second argument in the previous code example since the message was a simple plain text. When you want to send an HTML text, you change your text and this argument to “html.”

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
import ssl
port = 587
server = "smtp-mail.outlook.com"
sender = "example@outlook.com"
recipient = "example@gmail.com"
password = "strongpassword"
msg = MIMEMultipart()       
html_message = """
<html>
    <body>
        <p>
       This is HTML<br>
       </p>
    </body>
</html>
"""
msg.attach(MIMEText(html_message, "html"))
text = msg.as_string()
SSLcontext = ssl.create_default_context()
with smtplib.SMTP(server, port) as server:
    server.starttls(context=SSLcontext)
    server.login(sender, password)
    server.sendmail(sender, recipient, text) 

Python email HTML

 

Specify CC and BCC

The email.mime module also lets you specify CC and BCC recipients within your email message. To do so, you need to specify additional headers in your Multipart message.

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
import ssl
port = 587
server = "smtp-mail.outlook.com"
sender = "example@outlook.com"
recipient = "example@gmail.com"
password = "strongpassword"
msg = MIMEMultipart()       
message = """
    An email with CC and BCC
"""
msg['From']= sender
msg['To']= recipient
msg['Subject']= "This is TEST"
msg["Bcc"] = recipient
msg["Cc"] = 'example@gmail.com'
msg.attach(MIMEText(message, "plain"))
text = msg.as_string()
SSLcontext = ssl.create_default_context()
with smtplib.SMTP(server, port) as server:
    server.starttls(context=SSLcontext)
    server.login(sender, password)
    server.sendmail(sender, recipient, text)

Python specify CC and BCC in email

 

Send Email with attachment

Attachments are sent over the SMTP server in the form of binary files. To do so, you need to encode the attachments in base64, a common binary-to-text encoding scheme for encoding binary data into ASCII characters.

For instance, you can send a pdf file by reading it as an octet-stream with a MIMEBase instance and encoding it using the encoders module within Python’s email library.

from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib, ssl
from email import encoders
port = 587
server = "smtp-mail.outlook.com"
sender = "example@outlook.com"
recipient = "example@gmail.com"
password = "strongpassword"
msg = MIMEMultipart()       
message = "This email includes an attachment"
msg.attach(MIMEText(message, "plain"))
filename = "example.pdf"
with open(filename, "rb") as pdf:
    attachment = MIMEBase("application", "octet-stream")
    attachment.set_payload(pdf.read())
encoders.encode_base64(attachment)
attachment.add_header(
    "Content-Disposition",
    f"attachment; filename= {filename}",
)
msg.attach(attachment)
SSLcontext = ssl.create_default_context()
with smtplib.SMTP(server, port) as server:
    server.starttls(context=SSLcontext)
    server.login(sender, password)
    server.sendmail(sender, recipient, msg.as_string())

Python email attachment

 

Send Email with inline images

Sometimes you may want to embed images inside the HTML text. To do that, you can convert your image into a base64 encoded format and send it over.

Fortunately, Python has a library to do that for you. You can import the base64 library and use the b64encode() function that does this seamlessly.

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
import smtplib, ssl, base64
port = 587
server = "smtp-mail.outlook.com"
sender = "sender@outlook.com"
recipient = "receiver@gmail.com"
password = "strongPassword"
msg = MIMEMultipart()       
msg['From']= sender
msg['To']= recipient
msg['Subject']= "My subject"
filename = "example.jpg"
image = base64.b64encode(open(filename, "rb").read())
image_base64 = image.decode()
html_img = """
<html>
    <body>
        <p>
            <img src= "data:image/jpg;base64,{image_base64}">
       </p>
    </body>
</html>
"""
msg.attach(MIMEText(html_img, "html"))
text = msg.as_string()
context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
    server.starttls(context=context)
    server.login(sender, password )
    server.sendmail(sender, recipient, text)

Python email with inline images

 

Send Email to internationalized Email address (non ASCII)

Before emails gained worldwide recognition, they were mainly composed of ASCII characters and compiled with RFC 822 standard.

These days emails are sent internationally in many more character sets that are language-specific. To send internationalized emails, you need to use the email.header module, which encodes non-ASCII characters into RFC 2822-compliant format.

If your subject or sender fields contain non-ASCII characters, you can use the Header class to create a Header instance and pass the character set that the string was encoded in.

A corresponding decode_header() function decodes the encoded string into the original character set.

import email, smtplib, ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header, decode_header
subject = "Some non ASCII text"
receiver_email = "Pelé@example.com"
message = MIMEMultipart('mixed')
message['Subject'] = Header(subject, 'utf-8')
message['To'] = Header(receiver_email, 'iso-8859-1')
text = message.as_string()
print(text)
decode_header(text)

Python email NON-ACSII characters

 

Send DKIM signed mail

Using Python, you can send digitally signed emails using your private key. This is extremely useful in situations where authentication of a sender is essential.

To do that, you need to install a third-party package named dkimpy. You’ll need to install the package using the setup.py file.

Once done, you can import it by running the statement:

import dkim

Now you can generate a signature of your message using your private key (You’ll need to generate a public/private keypair for doing this). After that, you’ll have to attach the digital signature to your Multipart message and you’re all set.

import smtplib, dkim, time, os
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
port = 587
smtp_server = "smtp-mail.outlook.com"
sender_email = "sender@outlook.com"
receiver_email = "receiver@gmail.com"
password = "strongPassword"
msg = MIMEMultipart()       
msg['From']= sender_email
msg['To']= receiver_email
msg['Subject']= "This is TEST"
message = "A digitally signed email"
msg.attach(message)
headers=[b'from', b'to', b'subject']
privateKey = open(os.path.join('private_kry.pem')).read()
signature = dkim.sign(msg.as_string(), b'key1', b'mydomain.com', privateKey.encode(), include_headers=headers)
signature = signature.decode()
msg['DKIM-Signature'] = signature[len("DKIM-Signature: "):]
context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
    server.starttls(context=context)
    server.login(sender_email, password )
    server.sendmail(sender_email, receiver_email,msg)
print('Sent')

DKIM signed mail using Python

 

Send Emails to multiple recipients

The real benefits of email automation are reaped when you want to send personalized emails to multiple recipients. Perhaps you have a CSV file that contains many users’ names and email addresses.

You can read the CSV file in Python and loop over each line to retrieve the name and email of the recipient.

Once you have the recipient’s information, you can make your message more personalized by using str.format() and placeholders. Here’s how you do it:

import csv
import smtplib
import ssl
body = "Hello {name}!"
port = 587
server = "smtp-mail.outlook.com"
sender = "sender@outlook.com"
password = "strongPassword"
SSLcontext = ssl.create_default_context()
with smtplib.SMTP(server, port) as server:
    server.starttls(context = SSLcontext)
    server.login(sender_email, password)
    with open("file.csv") as file_handle:
        content = csv.reader(file_handle)
        next(content)  
        for name, email in content:
            server.sendmail(sender, email, body.format(name = name))

Python send email to multiple recipients

Leave a Reply

Your email address will not be published. Required fields are marked *