Updated On : Mar-03,2021 Tags email
email - How to Represent an Email Message in Python?

email - How to Represent an Email Message in Python?

Electronic mail (email) is a commonly used way to communicate messages between two devices connected on the internet nowadays. An email has evolved over time from being only comprised of ASCII text message to message with different types of data (HTML, audio, video, images, pdf files, etc). Python provides a module named email which lets us represent an email in python using an object. The email module tries to be as compliant as possible to RFC 5233 and RFC 6532 to represent an email message. The email module does not provide us with the functionality to send emails or retrieve emails from the server. Python provides other modules like smtplib and imaplib for these purposes. The email library just provides us with an API that lets us creates an object to represent an email message. These objects can then used by smtplib for sending mail. It also provides an API that lets us create an object representing email from string or bytes string.

As a part of this tutorial, we'll explain how we can create email message objects using an API provided by email module with simple and easy-to-understand examples. We'll also explain at last how we can send emails that we created and how we can convert bytes string to email object with single examples each.

Example 1: Create Simple Email Message

As a part of our first example, we'll explain how we can represent a simple text message using EmailMessage object of message sub-module of email module.


EmailMessage() -The message submodule of email module provides us with a class named EmailMessage which can be used to represent an email message. It has a list of methods that let us set contents of the mail, headers of the mails, add attachments to it, etc. The EmailMessage instance works like a dictionary which let us retrieve and set header value by using brackets as we do with a dictionary. It handles case-related mistakes in header names when matching (if you give from or From as key, then in both cases it'll retrieve Form header value).

Important Methods of EmailMessage Instance

  • add_header(name, value) - This method accepts header name and header value and adds it to the list of headers of the message.
  • set_content() - This method accepts string or bytes string as input and sets it as the content of the email.
  • as_string() - This method returns an entire message as string.
  • as_bytes() - This method returns an entire message as a byte string.

Our code for this example starts by creating an instance of EmailMessage. It then adds headers From, To and Subject to the email. We are then setting the string as the content of the email. We are then generating string and bytes string representation of the email and printing them.

We can easily send email represented by EmailMessage instance using smtplib library's send_message() method. Please feel free to check our tutorial on smtplib if you are interested in learning about how to send mail using Python.

In [20]:
import email

message = email.message.EmailMessage()

################ Set Headers ###################
message.add_header("From", "coderzcolumn07@gmail.com")
message.add_header("To", "sunny.2309@yahoo.in, mail2sunny.2309@gmail.com")
message.add_header("Subject", "Welcome to CoderzColumn")

##################### Set Main Content #####################
body = '''
Hi All,

How are you?

Regards,
CoderzColumn
'''

message.set_content(body)

############# Retrieve Message as a String ################
message_as_string = message.as_string()

print("\n============ Message as String ==============")
print(message_as_string)

############# Retrieve Message as a Byte String ################
message_as_bytes = message.as_bytes()
print("\n============ Message as Bytes ==============")
print(message_as_bytes)
============ Message as String ==============
From: coderzcolumn07@gmail.com
To: sunny.2309@yahoo.in, mail2sunny.2309@gmail.com
Subject: Welcome to CoderzColumn
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
MIME-Version: 1.0


Hi All,

How are you?

Regards,
CoderzColumn


============ Message as Bytes ==============
b'From: coderzcolumn07@gmail.com\nTo: sunny.2309@yahoo.in, mail2sunny.2309@gmail.com\nSubject: Welcome to CoderzColumn\nContent-Type: text/plain; charset="utf-8"\nContent-Transfer-Encoding: 7bit\nMIME-Version: 1.0\n\n\nHi All,\n\nHow are you?\n\nRegards,\nCoderzColumn\n'

Example 2: Create Email with Cc and Bcc Headers

As a part of our second example, we are demonstrating how we can add Cc and Bcc fields to our mail. We can add them using add_header() method as explained below. All of our remaining code is the same as our previous example with only the addition of two lines for Cc and Bcc headers.

In [41]:
import email

message = email.message.EmailMessage()

################ Set Headers ###################
message.add_header("From", "coderzcolumn07@gmail.com")
message.add_header("To", "sunny.2309@yahoo.in")
message.add_header("Cc", "coderzcolumn07@gmail.com")
message.add_header("Bcc", "mail2sunny.2309@gmail.com")
message.add_header("Subject", "Welcome to CoderzColumn")

##################### Set Main Content #####################
body = '''
Hi All,

How are you?

Regards,
CoderzColumn
'''

message.set_content(body)

############# Retrieve Message as a String ################
message_as_string = message.as_string()

print("\n============ Message as String ==============")
print(message_as_string)

print("\n========== Message Content ==================")
print(message.get_content())
============ Message as String ==============
From: coderzcolumn07@gmail.com
To: sunny.2309@yahoo.in
Cc: coderzcolumn07@gmail.com
Bcc: mail2sunny.2309@gmail.com
Subject: Welcome to CoderzColumn
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
MIME-Version: 1.0


Hi All,

How are you?

Regards,
CoderzColumn


========== Message Content ==================

Hi All,

How are you?

Regards,
CoderzColumn

Example 3: Clear Content and Headers of EmailMessage Instance

As a part of our third example, we are demonstrating how we can clear the contents of the mail (body part) and how we can clear contents and headers both using clear_content() and clear() methods of EmailMessage instance.


Important Methods of EmailMessage Instance

  • clear_content() - It removes only the contents of the message (body part) and not headers.
  • clear() - It removes both, the contents and headers of the message.

Our code for this example is almost the same as our previous example. We start by creating an instance of EmailMessage and add headers to it. We also set the body part of the message using set_content() method. We are then printing mail as a string. We are then calling clear_content() method and then printing the mail as a string. At last, we are calling clear() method and printing the mail as a string again.

In [43]:
import email

message = email.message.EmailMessage()

################ Set Headers ###################
message.add_header("From", "coderzcolumn07@gmail.com")
message.add_header("To", "sunny.2309@yahoo.in")
message.add_header("Cc", "coderzcolumn07@gmail.com")
message.add_header("Bcc", "mail2sunny.2309@gmail.com")
message.add_header("Subject", "Welcome to CoderzColumn")

##################### Set Main Content #####################
body = '''
Hi All,

How are you?

Regards,
CoderzColumn
'''

message.set_content(body)

############# Retrieve Message as a String ################
message_as_string = message.as_string()

print("\n============ Message as String ==============")
print(message_as_string)

message.clear_content()
print("\n========== Message as String ==================")
print(message.as_string())

message.clear()
print("\n========== Message as String ==================")
print(message.as_string())
============ Message as String ==============
From: coderzcolumn07@gmail.com
To: sunny.2309@yahoo.in
Cc: coderzcolumn07@gmail.com
Bcc: mail2sunny.2309@gmail.com
Subject: Welcome to CoderzColumn
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
MIME-Version: 1.0


Hi All,

How are you?

Regards,
CoderzColumn


========== Message as String ==================
From: coderzcolumn07@gmail.com
To: sunny.2309@yahoo.in
Cc: coderzcolumn07@gmail.com
Bcc: mail2sunny.2309@gmail.com
Subject: Welcome to CoderzColumn
MIME-Version: 1.0



========== Message as String ==================


Example 4: Retrieve Header Details

We'll use our fourth example to demonstrate how we can access details of the headers of the mail in a different way using different methods of EmailMessage instance.


Important Methods of EmailMessage Instance

  • items() - It returns a list of 2-value tuples where the first value is the name of the header and the second value is the value of that header.
  • keys() - It returns a list of header names in the mail.
  • values() - It returns the list of header values in the mail.
  • get(name,failobj=None) - It takes as input name of the header and returns it's value. If the header is missing then it'll return None.

Our code for this example starts by creating an instance of EmailMessage and then adds headers to it. It then adds the contents of the body of the message. We then print the mail as a string. We are then printing details of headers of the message using items() method. After that, we are printing header details of the mail using keys() and get() methods. At last, we are printing details of the headers using keys() method to retrieve header name and treating EmailMessage instance as a dictionary to retrieve header value. We are also calling values() method, at last, to print a list of header values for explanation purposes.

In [37]:
import email

message = email.message.EmailMessage()

################ Set Headers ###################
message.add_header("From", "coderzcolumn07@gmail.com")
message.add_header("To", "sunny.2309@yahoo.in")
message.add_header("Cc", "coderzcolumn07@gmail.com")
message.add_header("Bcc", "mail2sunny.2309@gmail.com")
message.add_header("Subject", "Welcome to CoderzColumn")

##################### Set Main Content #####################
body = '''
Hi All,

How are you?

Regards,
CoderzColumn
'''

message.set_content(body)

############# Retrieve Message as a String ################
message_as_string = message.as_string()

print("\n============ Message as String ==============")
print(message_as_string)

print("\n=========== Headers using items() ================")
for header,value in message.items():
    print("{:25s} - {}".format(header, value))

print("\n=========== Headers using keys() & get() ================")
for header in message.keys():
    print("{:25s} - {}".format(header, message.get(header)))

print("\n=========== Headers using keys() ================")
for header in message.keys():
    print("{:25s} - {}".format(header, message[header]))

print("\nHeader Values : {}".format(message.values()))
============ Message as String ==============
From: coderzcolumn07@gmail.com
To: sunny.2309@yahoo.in
Cc: coderzcolumn07@gmail.com
Bcc: mail2sunny.2309@gmail.com
Subject: Welcome to CoderzColumn
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
MIME-Version: 1.0


Hi All,

How are you?

Regards,
CoderzColumn


=========== Headers using items() ================
From                      - coderzcolumn07@gmail.com
To                        - sunny.2309@yahoo.in
Cc                        - coderzcolumn07@gmail.com
Bcc                       - mail2sunny.2309@gmail.com
Subject                   - Welcome to CoderzColumn
Content-Type              - text/plain; charset="utf-8"
Content-Transfer-Encoding - 7bit
MIME-Version              - 1.0

=========== Headers using keys() & get() ================
From                      - coderzcolumn07@gmail.com
To                        - sunny.2309@yahoo.in
Cc                        - coderzcolumn07@gmail.com
Bcc                       - mail2sunny.2309@gmail.com
Subject                   - Welcome to CoderzColumn
Content-Type              - text/plain; charset="utf-8"
Content-Transfer-Encoding - 7bit
MIME-Version              - 1.0

=========== Headers using keys() ================
From                      - coderzcolumn07@gmail.com
To                        - sunny.2309@yahoo.in
Cc                        - coderzcolumn07@gmail.com
Bcc                       - mail2sunny.2309@gmail.com
Subject                   - Welcome to CoderzColumn
Content-Type              - text/plain; charset="utf-8"
Content-Transfer-Encoding - 7bit
MIME-Version              - 1.0

Header Values : ['coderzcolumn07@gmail.com', 'sunny.2309@yahoo.in', 'coderzcolumn07@gmail.com', 'mail2sunny.2309@gmail.com', 'Welcome to CoderzColumn', 'text/plain; charset="utf-8"', '7bit', '1.0']

Example 5: Set and Retrieve Content-Type Details

As a part of our fifth example, we'll demonstrate how we can set and retrieve the content type of the mail using various methods of EmailMessage instance.


Important Methods of EmailMessage Instance

  • set_default_type(content_type) - It sets the default content type of the mail.
  • get_default_type() - It retrieves the default content type of the mail.
  • get_content_type() - It retrieves actual content type of the mail.
  • get_content_maintype() - It retrieves main content type of the mail.
  • get_content_subtype() - It retrieves sub content type of the mail.
  • is_attachment() - It check whether the EmailMessage instance is attachment message.
  • is_multipart() - It checks whether the EmailMessage instance is multiplart message.

Our code for this example like our previous example creates an instance of EmailMessage, sets headers, sets contents of the mail, and then prints email as a string. We are then calling all methods mentioned above to check the content types of the mail. We have also called set_default_type() to set content type of the mail as text/plain.

In [68]:
import email

message = email.message.EmailMessage()

################ Set Headers ###################
message.add_header("From", "coderzcolumn07@gmail.com")
message.add_header("To", "sunny.2309@yahoo.in")
message.add_header("Cc", "coderzcolumn07@gmail.com")
message.add_header("Bcc", "mail2sunny.2309@gmail.com")
message.add_header("Subject", "Welcome to CoderzColumn")

##################### Set Main Content #####################
body = '''
Hi All,

How are you?

Regards,
CoderzColumn
'''

message.set_content(body)
message.set_default_type("text/plain")

############# Retrieve Message as a String ################
message_as_string = message.as_string()

print("\n============ Message as String ==============")
print(message_as_string)

print("\n========= Content Type Details ==============")
print("Content Type          : {}".format(message.get_content_type()))
print("Content Main Type     : {}".format(message.get_content_maintype()))
print("Content Sub Type      : {}".format(message.get_content_subtype()))
print("Content Default Type  : {}".format(message.get_default_type()))
print("Is Attachment?        : {}".format(message.is_attachment()))
print("Is Multipart?         : {}".format(message.is_multipart()))
============ Message as String ==============
From: coderzcolumn07@gmail.com
To: sunny.2309@yahoo.in
Cc: coderzcolumn07@gmail.com
Bcc: mail2sunny.2309@gmail.com
Subject: Welcome to CoderzColumn
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
MIME-Version: 1.0


Hi All,

How are you?

Regards,
CoderzColumn


========= Content Type Details ==============
Content Type          : text/plain
Content Main Type     : text
Content Sub Type      : plain
Content Default Type  : text/plain
Is Attachment?        : False
Is Multipart?         : False

Example 6: Add Attachment and Get Body Contents from Multipart Mail

As a part of our sixth example, we are demonstrating how we can add attachments to the mail and then retrieve the body part of the mail. The mail becomes multipart once we add an attachment to it.


Important Methods of EmailMessage Instance

  • add_attachment(data,maintype=None,subtype=None,filename=None) - This method accepts attachment data as bytes along with their type and file name as input. It then adds creates a new message with attachment data and adds it as a subpart of the main mail message. It also sets the type of the mail as multipart.
  • get_body(preferencelist=('related', 'html', 'plain')) - This method returns message instance which best represents the body of the mail. It's generally returns message with content type text/plain or text/html. The preferencelist represents in which preference the message should be returned after checking content type.

Our code for this example uses mimetypes module to retrieve the MIME content type of the attachment file. We are attaching a JPEG image file as an attachment. We are first retrieving the MIME type of the attachment using guess_type() method of mimetypes module. We are then reading the contents of the JPEG image file as bytes and calling add_attachment() method to add an image as an attachment. We have passed the main type, subtype, and file name details for the attachment along with the data. We are then printing the content type of the mail. We are then calling get_body() method to retrieve the mail part which represents the actual body part of the mail and printing body contents.

In [64]:
import mimetypes
import email

message = email.message.EmailMessage()

################ Set Headers ###################
message.add_header("From", "coderzcolumn07@gmail.com")
message.add_header("To", "sunny.2309@yahoo.in")
message.add_header("Cc", "coderzcolumn07@gmail.com")
message.add_header("Bcc", "mail2sunny.2309@gmail.com")
message.add_header("Subject", "Welcome to CoderzColumn")

##################### Set Main Content #####################
body = '''
Hi All,

How are you?

Regards,
CoderzColumn
'''

message.set_content(body)

############# Add Attachments #############################
mime_type, encoding = mimetypes.guess_type("dr_apj_kalam.jpeg")
print("MIME Type of JPEG File : {}".format(mime_type))

with open("dr_apj_kalam.jpeg", "rb") as fp:
    image_data = fp.read()
    message.add_attachment(image_data, maintype=mime_type.split("/")[0],
                                       subtype=mime_type.split("/")[1],
                                       filename="kalam.jpeg")

########################## Content  Type #################
print("\nContent Type           : {}".format(message.get_content_type()))
print("Is Multipart?          : {}".format(message.is_multipart()))

#################### Message body ################
m = message.get_body()
print("\nMessage Body Type : {}".format(type(m)))
print("\n========= Message Body ===========")
print(m.get_content())
MIME Type of JPEG File : image/jpeg

Content Type           : multipart/mixed
Is Multipart?          : True

Message Body Type : <class 'email.message.EmailMessage'>

========= Message Body ===========

Hi All,

How are you?

Regards,
CoderzColumn

Example 7: Iterating Through Attachments

As a part of our seventh example, we'll explain how we can iterate through the list of attachments present in the mail using iter_attachments() method of EmailMessage instance.


Important Methods of EmailMessage Instance

  • iter_attachments() - This method returns list message parts of the main mail which are attachments and not the main body part. It skips the first occurrence of text/plain, text/html, multipart/related, and multipart/alternative.

Our code for this example uses much of the code that we have been using for the last many examples. We are adding three attachments (JPEG image, PDF file, and Zip file) to our mail as a part of the code. We are then retrieving each attachment using iter_attachments() methods and printing their information like content type, content-disposition, etc.

In [76]:
import mimetypes

message = email.message.EmailMessage()

################ Set Headers ###################
message.add_header("From", "coderzcolumn07@gmail.com")
message.add_header("To", "sunny.2309@yahoo.in")
message.add_header("Cc", "coderzcolumn07@gmail.com")
message.add_header("Bcc", "mail2sunny.2309@gmail.com")
message.add_header("Subject", "Welcome to CoderzColumn")

##################### Set Main Content #####################
body = '''
Hi All,

How are you?

Regards,
CoderzColumn
'''

message.set_content(body)

############# Add Attachments #############################
######### JPEG File ##################
mime_type, encoding = mimetypes.guess_type("dr_apj_kalam.jpeg")
print("MIME Type of JPEG File : {}".format(mime_type))

with open("dr_apj_kalam.jpeg", "rb") as fp:
    image_data = fp.read()
    message.add_attachment(image_data, maintype=mime_type.split("/")[0],
                                       subtype=mime_type.split("/")[1],
                                       filename="kalam.jpeg")

############ PDF File ######################
mime_type, encoding = mimetypes.guess_type("Deploying a Django Application to Google App Engine.pdf")
print("MIME Type of PDF File  : {}".format(mime_type))

with open("Deploying a Django Application to Google App Engine.pdf", "rb") as fp:
    pdf_data = fp.read()
    message.add_attachment(pdf_data, maintype=mime_type.split("/")[0],
                                       subtype=mime_type.split("/")[1],
                                       filename="gcloud.pdf")

############ Zip File ######################
mime_type, encoding = mimetypes.guess_type("docs.zip")
print("MIME Type of ZIP File  : {}".format(mime_type))

with open("docs.zip", "rb") as fp:
    image_data = fp.read()
    message.add_attachment(image_data, maintype=mime_type.split("/")[0],
                                       subtype=mime_type.split("/")[1],
                                       filename="docs.zip")


########################## Content  Type #################
print("\nContent Type           : {}".format(message.get_content_type()))
print("Is Multipart?          : {}".format(message.is_multipart()))
print("Content Disposition    : {}".format(message.get_content_disposition()))

################# Attachments #####################
print("\n================ Attachments ===================")
for attachment in message.iter_attachments():
    print("\nAttachment Type        : {}".format(type(attachment)))
    print("Content Type           : {}".format(attachment.get_content_type()))
    print("Is Multipart?          : {}".format(attachment.is_multipart()))
    print("Is Attachment?         : {}".format(attachment.is_attachment()))
    print("Content Disposition    : {}".format(attachment.get_content_disposition()))
MIME Type of JPEG File : image/jpeg
MIME Type of PDF File  : application/pdf
MIME Type of ZIP File  : application/zip

Content Type           : multipart/mixed
Is Multipart?          : True
Content Disposition    : None

================ Attachments ===================

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : image/jpeg
Is Multipart?          : False
Is Attachment?         : True
Content Disposition    : attachment

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : application/pdf
Is Multipart?          : False
Is Attachment?         : True
Content Disposition    : attachment

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : application/zip
Is Multipart?          : False
Is Attachment?         : True
Content Disposition    : attachment

Example 8: Iterate Through Sub Parts of the Mail

As a part of our eighth example, we are demonstrating how we can iterate over sub-parts of the mail using iter_parts() method of EmailMessage instance.


Important Methods of EmailMessage Instance

  • iter_parts() - This method returns sub-parts of the message.

Our code for this example is almost the same as our code from our previous example. We are adding three attachments to our mail like our previous example. We are then retrieving sub-parts of the mail using iter_parts() method and printing their details like content type, disposition, etc. We can notice from the output that, this method returns one extra message part (along with attachments), which is of type text/plain and represent the body part of the message. The main message is of type multipart/mixed.

In [80]:
import mimetypes

message = email.message.EmailMessage()

################ Set Headers ###################
message.add_header("From", "coderzcolumn07@gmail.com")
message.add_header("To", "sunny.2309@yahoo.in")
message.add_header("Cc", "coderzcolumn07@gmail.com")
message.add_header("Bcc", "mail2sunny.2309@gmail.com")
message.add_header("Subject", "Welcome to CoderzColumn")

##################### Set Main Content #####################
body = '''
Hi All,

How are you?

Regards,
CoderzColumn
'''

message.set_content(body)

############# Add Attachments #############################
######### JPEG File ##################
mime_type, encoding = mimetypes.guess_type("dr_apj_kalam.jpeg")
print("MIME Type of JPEG File : {}".format(mime_type))

with open("dr_apj_kalam.jpeg", "rb") as fp:
    image_data = fp.read()
    message.add_attachment(image_data, maintype=mime_type.split("/")[0],
                                       subtype=mime_type.split("/")[1],
                                       filename="kalam.jpeg")

############ PDF File ######################
mime_type, encoding = mimetypes.guess_type("Deploying a Django Application to Google App Engine.pdf")
print("MIME Type of PDF File  : {}".format(mime_type))

with open("Deploying a Django Application to Google App Engine.pdf", "rb") as fp:
    pdf_data = fp.read()
    message.add_attachment(pdf_data, maintype=mime_type.split("/")[0],
                                       subtype=mime_type.split("/")[1],
                                       filename="gcloud.pdf")

############ Zip File ######################
mime_type, encoding = mimetypes.guess_type("docs.zip")
print("MIME Type of ZIP File  : {}".format(mime_type))

with open("docs.zip", "rb") as fp:
    image_data = fp.read()
    message.add_attachment(image_data, maintype=mime_type.split("/")[0],
                                       subtype=mime_type.split("/")[1],
                                       filename="docs.zip")


########################## Content  Type #################
print("\nContent Type           : {}".format(message.get_content_type()))
print("Is Multipart?          : {}".format(message.is_multipart()))
print("Content Disposition    : {}".format(message.get_content_disposition()))

################# Message Parts #####################
print("\n================ Message Parts ===================")
for part in message.iter_parts():
    print("\nAttachment Type        : {}".format(type(part)))
    print("Content Type           : {}".format(part.get_content_type()))
    print("Is Multipart?          : {}".format(part.is_multipart()))
    print("Is Attachment?         : {}".format(part.is_attachment()))
    print("Content Disposition    : {}".format(part.get_content_disposition()))
MIME Type of JPEG File : image/jpeg
MIME Type of PDF File  : application/pdf
MIME Type of ZIP File  : application/zip

Content Type           : multipart/mixed
Is Multipart?          : True
Content Disposition    : None

================ Message Parts ===================

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : text/plain
Is Multipart?          : False
Is Attachment?         : False
Content Disposition    : None

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : image/jpeg
Is Multipart?          : False
Is Attachment?         : True
Content Disposition    : attachment

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : application/pdf
Is Multipart?          : False
Is Attachment?         : True
Content Disposition    : attachment

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : application/zip
Is Multipart?          : False
Is Attachment?         : True
Content Disposition    : attachment

Example 9: Iterate Through All Message Parts

As a part of our ninth example, we'll explain how we can access all parts of the message using walk() method of EmailMessage instance.


Important Methods of EmailMessage Instance

  • walk() - This method returns a generator that returns all parts and sub-parts of the message one by one.

Our code for this example is almost the same as our code for the previous two examples. We are looping through message parts using walk() method at last and printing details of the message like content type, disposition, etc. We can notice from the output that this method also returns a message with content type multipart/mixed along with attachments and main body part (text/plain).

In [86]:
import mimetypes

message = email.message.EmailMessage()

################ Set Headers ###################
message.add_header("From", "coderzcolumn07@gmail.com")
message.add_header("To", "sunny.2309@yahoo.in")
message.add_header("Cc", "coderzcolumn07@gmail.com")
message.add_header("Bcc", "mail2sunny.2309@gmail.com")
message.add_header("Subject", "Welcome to CoderzColumn")

##################### Set Main Content #####################
body = '''
Hi All,

How are you?

Regards,
CoderzColumn
'''

message.set_content(body)

############# Add Attachments #############################
######### JPEG File ##################
mime_type, encoding = mimetypes.guess_type("dr_apj_kalam.jpeg")
print("MIME Type of JPEG File : {}".format(mime_type))

with open("dr_apj_kalam.jpeg", "rb") as fp:
    image_data = fp.read()
    message.add_attachment(image_data, maintype=mime_type.split("/")[0],
                                       subtype=mime_type.split("/")[1],
                                       filename="kalam.jpeg")

############ PDF File ######################
mime_type, encoding = mimetypes.guess_type("Deploying a Django Application to Google App Engine.pdf")
print("MIME Type of PDF File  : {}".format(mime_type))

with open("Deploying a Django Application to Google App Engine.pdf", "rb") as fp:
    pdf_data = fp.read()
    message.add_attachment(pdf_data, maintype=mime_type.split("/")[0],
                                       subtype=mime_type.split("/")[1],
                                       filename="gcloud.pdf")

############ Zip File ######################
mime_type, encoding = mimetypes.guess_type("docs.zip")
print("MIME Type of ZIP File  : {}".format(mime_type))

with open("docs.zip", "rb") as fp:
    image_data = fp.read()
    message.add_attachment(image_data, maintype=mime_type.split("/")[0],
                                       subtype=mime_type.split("/")[1],
                                       filename="docs.zip")


########################## Content  Type #################
print("\nContent Type           : {}".format(message.get_content_type()))
print("Is Multipart?          : {}".format(message.is_multipart()))
print("Content Disposition    : {}".format(message.get_content_disposition()))

################# Message Parts #####################
print("\n================ Message Parts ===================")
for part in message.walk():
    print("\nAttachment Type        : {}".format(type(part)))
    print("Content Type           : {}".format(part.get_content_type()))
    print("Is Multipart?          : {}".format(part.is_multipart()))
    print("Is Attachment?         : {}".format(part.is_attachment()))
    print("Content Disposition    : {}".format(part.get_content_disposition()))
MIME Type of JPEG File : image/jpeg
MIME Type of PDF File  : application/pdf
MIME Type of ZIP File  : application/zip

Content Type           : multipart/mixed
Is Multipart?          : True
Content Disposition    : None

================ Message Parts ===================

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : multipart/mixed
Is Multipart?          : True
Is Attachment?         : False
Content Disposition    : None

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : text/plain
Is Multipart?          : False
Is Attachment?         : False
Content Disposition    : None

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : image/jpeg
Is Multipart?          : False
Is Attachment?         : True
Content Disposition    : attachment

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : application/pdf
Is Multipart?          : False
Is Attachment?         : True
Content Disposition    : attachment

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : application/zip
Is Multipart?          : False
Is Attachment?         : True
Content Disposition    : attachment

Example 10: Convert a Message to Multipart/Mixed

As a part of our tenth example, we'll explain how we can convert a non-multipart message to a multipart message using make_mixed() method of EmailMessage instance.


Important Methods of EmailMessage Instance

  • make_mixed() - This method converts a non-multipart, multipart/related and multipart/alternative message to multipart/mixed message.

Our code for this example first creates a mail and sets its main body like we have been doing for the last many examples. It then prints information about message like content type, content-disposition, and message sub-parts details. We are then calling make_mixed() method to convert non-multipart message to multipart. We are then again printing information about message like content type, content-disposition, and message sub-parts details. We can notice that mail's content type before was text/plain and it does not have sub-parts. After we called make_mixed() and converted message, now the content type has changed to multipart/mixed and mail has sub-part which is of typetext/plain. The main body part (text/plain) has been moved inside after the conversation.

In [85]:
import mimetypes

message = email.message.EmailMessage()

################ Set Headers ###################
message.add_header("From", "coderzcolumn07@gmail.com")
message.add_header("To", "sunny.2309@yahoo.in")
message.add_header("Cc", "coderzcolumn07@gmail.com")
message.add_header("Bcc", "mail2sunny.2309@gmail.com")
message.add_header("Subject", "Welcome to CoderzColumn")

##################### Set Main Content #####################
body = '''
Hi All,

How are you?

Regards,
CoderzColumn
'''

message.set_content(body)

print("\n============= Details Beofre Making multipart/mixed============")

print("\nContent Type           : {}".format(message.get_content_type()))
print("Is Multipart?          : {}".format(message.is_multipart()))
print("Content Disposition    : {}".format(message.get_content_disposition()))

print("\n================ Message Parts ===================")
for part in message.walk():
    print("\nAttachment Type        : {}".format(type(part)))
    print("Content Type           : {}".format(part.get_content_type()))
    print("Is Multipart?          : {}".format(part.is_multipart()))
    print("Is Attachment?         : {}".format(part.is_attachment()))
    print("Content Disposition    : {}".format(part.get_content_disposition()))

message.make_mixed() ### Make Message multipart/mixed

print("\n============= Details After Making multipart/mixed============")
########################## Content  Type #################
print("\nContent Type           : {}".format(message.get_content_type()))
print("Is Multipart?          : {}".format(message.is_multipart()))
print("Content Disposition    : {}".format(message.get_content_disposition()))

################# Message Parts #####################
print("\n================ Message Parts ===================")
for part in message.walk():
    print("\nAttachment Type        : {}".format(type(part)))
    print("Content Type           : {}".format(part.get_content_type()))
    print("Is Multipart?          : {}".format(part.is_multipart()))
    print("Is Attachment?         : {}".format(part.is_attachment()))
    print("Content Disposition    : {}".format(part.get_content_disposition()))
============= Details Beofre Making multipart/mixed============

Content Type           : text/plain
Is Multipart?          : False
Content Disposition    : None

================ Message Parts ===================

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : text/plain
Is Multipart?          : False
Is Attachment?         : False
Content Disposition    : None

============= Details After Making multipart/mixed============

Content Type           : multipart/mixed
Is Multipart?          : True
Content Disposition    : None

================ Message Parts ===================

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : multipart/mixed
Is Multipart?          : True
Is Attachment?         : False
Content Disposition    : None

Attachment Type        : <class 'email.message.EmailMessage'>
Content Type           : text/plain
Is Multipart?          : False
Is Attachment?         : False
Content Disposition    : None

Example 11: Send mail using SMTP

As a part of our eleventh example, we are demonstrating how we can send mail using Python. The mail that is represented by EmailMessage instance.

Our code for this example creates a mail the same way as our previous examples with three attachments. It then sends mail using send_message() method of SMTP_SSL instance available from smtplib module of Python.

Please make a NOTE that we have not covered the working of smtplib module as a part of this tutorial. We have a different tutorial for the same. If you are interested in learning about the same then please feel free to check it.

In [1]:
import smtplib
import time
import email

################# SMTP SSL ################################
with smtplib.SMTP_SSL(host="smtp.gmail.com", port=465) as smtp_ssl:
    print("Connection Object : {}".format(smtp_ssl))

    ######### Log In to mail account ############################
    print("\nLogging In.....")
    resp_code, response = smtp_ssl.login(user="mail2sunny.2309@gmail.com", password="app_password")

    print("Response Code : {}".format(resp_code))
    print("Response      : {}".format(response.decode()))

    ################ Send Mail ########################
    print("\nSending Mail..........")

    message = email.message.EmailMessage()

    message["From"] = "mail2sunny.2309@gmail.com"
    message["To"] = ["coderzcolumn07@gmail.com", ]
    message["cc"] = ["mail2sunny.2309@gmail.com",]
    message["Bcc"] = ["sunny.2309@yahoo.in", ]

    message["Subject"] =  "Mail with attachments"

    body = '''
    Hello All,

    Please find attached file.

    Regards,
    CoderzColumn
    '''
    message.set_content(body)

    ### Attach JPEG Image.
    with open("dr_apj_kalam.jpeg", mode="rb") as fp:
        img_content = fp.read()
        message.add_attachment(img_content, maintype="image", subtype="jpeg", filename="kalam.jpeg")

    ### Attach PDF Image.
    with open("Deploying a Django Application to Google App Engine.pdf", mode="rb") as fp:
        pdf_content = fp.read()
        message.add_attachment(pdf_content, maintype="application", subtype="pdf", filename="doc.pdf")

    ### Attach Zip Image.
    with open("docs.zip", mode="rb") as fp:
        zip_content = fp.read()
        message.add_attachment(zip_content, maintype="application", subtype="zip", filename="docs.zip")

    ### Send Message
    response = smtp_ssl.send_message(msg=message)

    print("List of Failed Recipients : {}".format(response))
Connection Object : <smtplib.SMTP_SSL object at 0x7f43401df4f0>

Logging In.....
Response Code : 235
Response      : 2.7.0 Accepted

Sending Mail..........
List of Failed Recipients : {}

Example 12: Retrieve Mail using IMAP

As a part of our twelfth example, we are demonstrating how we can read a mail using Python. We'll be reading the mail which we sent in our previous example and print details of the mail which we have explained in our previous examples.

Our code for this example reads the latest email from Gmail INBOX which is the mail that we sent in our last example using IMAP4_SSL instance of imaplib library. We have then used from_bytes() method of email module to transfer mail from bytes format to object of type Message which represents the mail in Python. The Message instance is almost the same as EmailMessage instance with the only change that it does not have some methods available with EmailMessage and it was part of Legacy API of email module which is still maintained.

Please make a NOTE that we have not covered the working of imaplib module as a part of this tutorial. We have a different tutorial for the same. If you are interested in learning about the same then please feel free to check it.

In [16]:
import imaplib
import email

################ IMAP SSL ##############################

with imaplib.IMAP4_SSL(host="imap.gmail.com", port=imaplib.IMAP4_SSL_PORT) as imap_ssl:
    print("Connection Object : {}".format(imap_ssl))

    ############### Login to Mailbox ######################
    print("Logging into mailbox...")
    resp_code, response = imap_ssl.login("mail2sunny.2309@gmail.com", "app_password")
    print("Response Code : {}".format(resp_code))
    print("Response      : {}\n".format(response[0].decode()))

    ############### Set Mailbox #############
    resp_code, mail_count = imap_ssl.select(mailbox="INBOX", readonly=True)

    ############### Retrieve Mail IDs for given Directory #############   
    resp_code, mails = imap_ssl.search(None, "ALL")

    ############### Display Few Messages for given Directory #############
    mail_id = mails[0].decode().split()[-1]
    print("================== Start of Mail [{}] ====================\n".format(mail_id))
    resp_code, mail_data = imap_ssl.fetch(mail_id, '(RFC822)') ## Fetch mail data.
    message = email.message_from_bytes(mail_data[0][1]) ## Construct Message from mail data
    print("From       : {}".format(message.get("From")))
    print("To         : {}".format(message.get("To")))
    print("Cc        : {}".format(message.get("Cc")))
    print("Bcc        : {}".format(message.get("Bcc")))
    print("Date       : {}".format(message.get("Date")))
    print("Subject    : {}".format(message.get("Subject")))
    print("Body : ")
    for part in message.walk():
        if part.get_content_type() == "text/plain":
            body_lines = part.as_string().split("\n")
            print("\n".join(body_lines[:12])) ### Print first 12 lines of message

    print("\n\t============= Attachments ===================")
    for attachment in message.walk():
        content_type = attachment.get_content_type()
        if not (content_type.startswith("text") or content_type.startswith("multi")):
            print("\n\tAttachment Type        : {}".format(attachment.get_content_disposition()))
            print("\tFile Name              : {}".format(attachment.get_filename()))
            print("\tContent Type           : {}".format(attachment.get_content_type()))

    print("\n================== End of Mail [{}] ====================\n".format(mail_id))

    ############# Close Selected Mailbox #######################
    print("\nClosing selected mailbox....")
    imap_ssl.close()
Connection Object : <imaplib.IMAP4_SSL object at 0x7f4343aaee50>
Logging into mailbox...
Response Code : OK
Response      : mail2sunny.2309@gmail.com authenticated (Success)

================== Start of Mail [3065] ====================

From       : mail2sunny.2309@gmail.com
To         : coderzcolumn07@gmail.com
Cc        : mail2sunny.2309@gmail.com
Bcc        : sunny.2309@yahoo.in
Date       : Wed, 03 Mar 2021 03:07:05 -0800 (PST)
Subject    : Mail with attachments
Body :
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit


    Hello All,

    Please find attached file.

    Regards,
    CoderzColumn



	============= Attachments ===================

	Attachment Type        : attachment
	File Name              : kalam.jpeg
	Content Type           : image/jpeg

	Attachment Type        : attachment
	File Name              : doc.pdf
	Content Type           : application/pdf

	Attachment Type        : attachment
	File Name              : docs.zip
	Content Type           : application/zip

================== End of Mail [3065] ====================


Closing selected mailbox....

This ends our small tutorial explaining how we can represent mail in Python using email module. We explained how we can create a mail with different headers and different content types. Please feel free to let us know your views in the comments section.

References



Sunny Solanki  Sunny Solanki