Python Parse Html Email

Parsing the HTML content in email – Stack Overflow

I’m trying to write a python script to read my emails.
I’m able to get most of the things properly like To, From, Subject.
But in the body, I get the text as well as it’s HTML code too as shown below.
Below is the part of code that does the extraction of content from the email
email_message = ssage_from_string(raw_email)
print ‘To:’, email_message[‘To’]
print ‘Sent from:’, email_message[‘From’]
print ‘Date:’, email_message[‘Date’]
print ‘Subject:’, email_message[‘Subject’]
print ‘*’*30, ‘MESSAGE’, ‘*’*30
maintype = t_content_maintype()
#print maintype
if maintype == ‘multipart’:
for part in t_payload():
if t_content_maintype() == ‘text’:
print t_payload()
elif maintype == ‘text’:
print ‘*’*69
Git link for the complete code: Email-parser
How to get rid of that HTML code and get only the plain text?
email.parser: Parsing email messages — Python 3.10.0 ...

email.parser: Parsing email messages — Python 3.10.0 …

Source code: Lib/email/
Message object structures can be created in one of two ways: they can be
created from whole cloth by creating an EmailMessage
object, adding headers using the dictionary interface, and adding payload(s)
using set_content() and related methods, or
they can be created by parsing a serialized representation of the email
The email package provides a standard parser that understands most email
document structures, including MIME documents. You can pass the parser a
bytes, string or file object, and the parser will return to you the root
EmailMessage instance of the object structure. For
simple, non-MIME messages the payload of this root object will likely be a
string containing the text of the message. For MIME messages, the root object
will return True from its is_multipart()
method, and the subparts can be accessed via the payload manipulation methods,
such as get_body(),
iter_parts(), and
There are actually two parser interfaces available for use, the Parser
API and the incremental FeedParser API. The Parser API is
most useful if you have the entire text of the message in memory, or if the
entire message lives in a file on the file system. FeedParser is more
appropriate when you are reading the message from a stream which might block
waiting for more input (such as reading an email message from a socket). The
FeedParser can consume and parse the message incrementally, and only
returns the root object when you close the parser.
Note that the parser can be extended in limited ways, and of course you can
implement your own parser completely from scratch. All of the logic that
connects the email package’s bundled parser and the
EmailMessage class is embodied in the policy
class, so a custom parser can create message object trees any way it finds
necessary by implementing custom versions of the appropriate policy
FeedParser API¶
The BytesFeedParser, imported from the email. feedparser module,
provides an API that is conducive to incremental parsing of email messages,
such as would be necessary when reading the text of an email message from a
source that can block (such as a socket). The BytesFeedParser can of
course be used to parse an email message fully contained in a bytes-like
object, string, or file, but the BytesParser API may be more
convenient for such use cases. The semantics and results of the two parser
APIs are identical.
The BytesFeedParser’s API is simple; you create an instance, feed it a
bunch of bytes until there’s no more to feed it, then close the parser to
retrieve the root message object. The BytesFeedParser is extremely
accurate when parsing standards-compliant messages, and it does a very good job
of parsing non-compliant messages, providing information about how a message
was deemed broken. It will populate a message object’s
defects attribute with a list of any
problems it found in a message. See the module for the
list of defects that it can find.
Here is the API for the BytesFeedParser:
class (_factory=None, *, mpat32)¶
Create a BytesFeedParser instance. Optional _factory is a
no-argument callable; if not specified use the
message_factory from the policy. Call
_factory whenever a new message object is needed.
If policy is specified use the rules it specifies to update the
representation of the message. If policy is not set, use the
compat32 policy, which maintains backward
compatibility with the Python 3. 2 version of the email package and provides
Message as the default factory. All other policies
provide EmailMessage as the default _factory. For
more information on what else policy controls, see the
policy documentation.
Note: The policy keyword should always be specified; The default will
change to in a future version of Python.
New in version 3. 2.
Changed in version 3. 3: Added the policy keyword.
Changed in version 3. 6: _factory defaults to the policy message_factory.
Feed the parser some more data. data should be a bytes-like
object containing one or more lines. The lines can be partial and the
parser will stitch such partial lines together properly. The lines can
have any of the three common line endings: carriage return, newline, or
carriage return and newline (they can even be mixed).
Complete the parsing of all previously fed data and return the root
message object. It is undefined what happens if feed() is called
after this method has been called.
Works like BytesFeedParser except that the input to the
feed() method must be a string. This is of limited
utility, since the only way for such a message to be valid is for it to
contain only ASCII text or, if utf8 is
True, no binary attachments.
Parser API¶
The BytesParser class, imported from the module,
provides an API that can be used to parse a message when the complete contents
of the message are available in a bytes-like object or file. The
module also provides Parser for parsing strings,
and header-only parsers, BytesHeaderParser and
HeaderParser, which can be used if you’re only interested in the
headers of the message. BytesHeaderParser and HeaderParser
can be much faster in these situations, since they do not attempt to parse the
message body, instead setting the payload to the raw body.
class (_class=None, *, mpat32)¶
Create a BytesParser instance. The _class and policy
arguments have the same meaning and semantics as the _factory
and policy arguments of BytesFeedParser.
Changed in version 3. 3: Removed the strict argument that was deprecated in 2. 4. Added the
policy keyword.
Changed in version 3. 6: _class defaults to the policy message_factory.
parse(fp, headersonly=False)¶
Read all the data from the binary file-like object fp, parse the
resulting bytes, and return the message object. fp must support
both the readline() and the read()
The bytes contained in fp must be formatted as a block of RFC 5322
(or, if utf8 is True, RFC 6532)
style headers and header continuation lines, optionally preceded by an
envelope header. The header block is terminated either by the end of the
data or by a blank line. Following the header block is the body of the
message (which may contain MIME-encoded subparts, including subparts
with a of 8bit).
Optional headersonly is a flag specifying whether to stop parsing after
reading the headers or not. The default is False, meaning it parses
the entire contents of the file.
parsebytes(bytes, headersonly=False)¶
Similar to the parse() method, except it takes a bytes-like
object instead of a file-like object. Calling this method on a
bytes-like object is equivalent to wrapping bytes in a
BytesIO instance first and calling parse().
Optional headersonly is as with the parse() method.
Exactly like BytesParser, except that headersonly
defaults to True.
New in version 3. 3.
This class is parallel to BytesParser, but handles string input.
Changed in version 3. 3: Removed the strict argument. Added the policy keyword.
Read all the data from the text-mode file-like object fp, parse the
resulting text, and return the root message object. fp must support
both the readline() and the
read() methods on file-like objects.
Other than the text mode requirement, this method operates like
parsestr(text, headersonly=False)¶
Similar to the parse() method, except it takes a string object
instead of a file-like object. Calling this method on a string is
equivalent to wrapping text in a StringIO instance first
and calling parse().
Exactly like Parser, except that headersonly
Since creating a message object structure from a string or a file object is such
a common task, four functions are provided as a convenience. They are available
in the top-level email package namespace.
ssage_from_bytes(s, _class=None, *, mpat32)¶
Return a message object structure from a bytes-like object. This is
equivalent to BytesParser(). parsebytes(s). Optional _class and
policy are interpreted as with the BytesParser class
ssage_from_binary_file(fp, _class=None, *, mpat32)¶
Return a message object structure tree from an open binary file
object. This is equivalent to BytesParser()(fp). _class and
ssage_from_string(s, _class=None, *, mpat32)¶
Return a message object structure from a string. This is equivalent to
Parser(). parsestr(s). _class and policy are interpreted as
with the Parser class constructor.
ssage_from_file(fp, _class=None, *, mpat32)¶
Return a message object structure tree from an open file object.
This is equivalent to Parser()(fp). _class and policy are
interpreted as with the Parser class constructor.
Here’s an example of how you might use message_from_bytes() at an
interactive Python prompt:
>>> import email
>>> msg = ssage_from_bytes(myBytes)
Additional notes¶
Here are some notes on the parsing semantics:
Most non-multipart type messages are parsed as a single message
object with a string payload. These objects will return False for
is_multipart(), and
iter_parts() will yield an empty list.
All multipart type messages will be parsed as a container message
object with a list of sub-message objects for their payload. The outer
container message will return True for
iter_parts() will yield a list of subparts.
Most messages with a content type of message/* (such as
message/delivery-status and message/rfc822) will also
be parsed as container object containing a list payload of length 1. Their
is_multipart() method will return True.
The single element yielded by iter_parts()
will be a sub-message object.
Some non-standards-compliant messages may not be internally consistent about
their multipart-edness. Such messages may have a
header of type multipart, but their
is_multipart() method may return False.
If such messages were parsed with the FeedParser,
they will have an instance of the
MultipartInvariantViolationDefect class in their
defects attribute list. See for details.
Creating an Email Parser with Python and SQL - Towards ...

Creating an Email Parser with Python and SQL – Towards …

Boost your productivity by automatically extracting data from your emailsPhoto by Solen Feyissa on UnsplashHuh, what’s that? An email … parser? You might be wondering what an email parser is, and why you might need short, an email parser is a software that looks for and extracts data from inbound emails and attachments. More importantly, an email parser uses conditional processing to pull the specific data that matters to why does this matter? If you’ve ever spent any time working a regular office job, you’ve probably become intimately familiar with reports, and by extension, copy-pasting lines of text from Microsoft Outlook to Excel or might even end up doing the same report, week after week. Add in formatting and spellchecking, and this ends up as a huge time drain when you could be focusing on more important good news is that you can automate most of this process with Python and this post, I’ll cover how to open Outlook emails with Python and extract the body text as HTML. I’ll then cover how to parse this in Python and how to upload the final data to a SQL database. From there, you can write this data to Excel or transform it into a Pandas ’ll be using a few key Python libraries here, namely os, sqlite3 and start off, we’ll first need to decide what we want to extract from our emails. For example, let’s say we have a bunch of emails that each contain a list of news articles like this:Let’s then say that we want to extract the header of each bullet point, which includes the title, the publication, media platforms, and URL links. In short, we want to take the entire header of each bullet point, then break it down into four different header that we want to extract text fromOur pseudocode so far should look something like this:1. Create list of emails that we want to parse2. Open first email3. Iterate over each bullet point4. Extract data from bullet point5. Upload data from bullet point to a database6. Repeat until all data is parsed, then move to next emailBefore parsing our emails, we’ll first want to set up a SQL database with Python. We’ll do this by establishing a connection to the SQLite database with a connection object that we’ll call db. # Create & connect to databasedb = nnect(“”)If it doesn’t already exist, a new database will be created as We can then create tables in our database that our email parser can write to later on. # Create empty tablesdb. execute(“””CREATE TABLE IF NOT EXISTS “articles” (“id” INTEGER, “title” TEXT UNIQUE, “publication” TEXT, PRIMARY KEY(“id” AUTOINCREMENT))”””)db. execute(“””CREATE TABLE IF NOT EXISTS “links” (“article_id” INTEGER, “link0” TEXT, “link1” TEXT, “link2” TEXT, PRIMARY KEY(“article_id”))”””)db. execute(“””CREATE TABLE IF NOT EXISTS “platforms” (“article_id” INTEGER, “platform0” TEXT, “platform1” TEXT, “platform2” TEXT, PRIMARY KEY(“article_id”))”””)In essence, we’re creating three tables, where our main table is ‘articles’, which has a one-to-many relationship with ‘platforms’ and ‘links’. In other words, this reflects how one article can have many different platforms and database schemaYou’ll want to move the emails that you want to parse from Outlook to a folder. The simplest method to do this is by dragging and monstration of the drag-and-drop methodNext, create a variable storing the folder path of your emails. You can do this manually e. g. folder_path = r‘C:\Users\Username\EmailFolder’ or with tkinter and os, which will generate a file explorer prompt to select a folder. # Create an folder input dialog with tkinterfolder_path = (askdirectory(title=’Select Folder’))Obtaining our folder path with tkinterHere, we’re using a file input prompt created with tkinter to save our folder path, then normalizing the path with os to remove any redundant ’ll then want to obtain the path headings of each email. We can do this with stdir(), which gives a list of all files in the specified directory. # Initialise & populate list of emailsemail_list = [file for file in stdir(folder_path) if file. endswith(“”)]This will save the file name of each email in list that we can access, you’ll want to create an object that will allow us to control Outlook from Python. This is enabled through the pywin32 library that helps to connect Python to Outlook via the Microsoft Outlook Messaging API (MAPI). # Connect to Outlook with MAPIoutlook = (“lication”). GetNamespace(“MAPI”)With this, we can begin to open each item as a HTML object, and use regular expressions i. e. Regex to extract the body text of each conventional wisdom dictates that you shouldn’t use Regex to parse HTML, we’re not worried about this here, as we’re only looking to extract very specific text snippets out of a standard email format (Some commercial email parsers like Parseur are heavily built around Regex) this point, Regex can be used to narrow down the specific data that you want to extract. # Iterate through every emailfor i, _ in enumerate(email_list): # Create variable storing info from current email being parsed msg = SharedItem((folder_path, email_list[i])) # Search email HTML for body text regex = (r”"use strict";function wprRemoveCPCSS(){var preload_stylesheets=document.querySelectorAll('link[data-rocket-async="style"][rel="preload"]');if(preload_stylesheets&&0“, MLBody) body = ()This is how the first bullet point of our email might look as HTML:The HTML view of our email snippetOkay — so we can see that there are several key characteristics here, namely that our data exists as a bulleted list or li class=MsoListParagraph. We can use Regex to extract each bullet point. # Search email body text for unique entriespattern = r”li class=MsoListParagraph([\s\S]*? )

“results = ndall(pattern, body)Each bullet point is extracted as a string, and each string is stored in a list. Our first bullet point should look something like this with Regex:Narrowing down our HTML body text with Regex ()To retrieve our title and publication, we can use Regex again. This time, we’ll also use call html. unescape() on our text to help translate our HTML to string e. &8211; → – (a unicode dash) = (r”[^<>]+(? =\(|sans-serif’>([\s\S]*? ))”, header)# HTML unescape to get remove remaining HTMLtitle_pub = html. unescape(())Our regex returns the highlighted text as the variable aboveFrom here, it’s as simple as splitting our text. We can use split_list = (“–”) to give us a list: [“New Arrival: Dell G Series Gaming Computers”, “Tech4tea”] can then remove any redundant whitespaces and save each item as a = split_list[0]()publication = split_list[1]()That’s two down! To get our media platforms, we’ll use a more straightforward method. # List of publications to check forplatform_list = [“Online”, “Facebook”, “Instagram”, “Twitter”, “LinkedIn”, “Youtube”]# Create empty list to store publicationsplatform = []# Iterate and check for each item in my first listfor p in platform_list: if p in header: (p)This will give us a list of publications: [“Online”, “Facebook”, “LinkedIn”]Now for the URLs:# Find all links using regexlinks = ndall(r”“, header)This will then give us the characters highlighted in green below:Pretty neat, right? Our data so far should look something like this:Title: New Arrival: Dell G Series Gaming ComputersPublication: Tech4teaPlatform: [‘Online’, ‘Facebook’, ‘LinkedIn’]Links: [‘’, ‘’, ‘’]The final step in this process is to upload each piece of data to our SQL ’ll start by uploading our title and publication data. This can be accomplished with the following code:# Insert title & pub by substituting values into each? placeholderdb. execute(“INSERT INTO articles (title, publication) VALUES (?,? )”, (title, publication))Uploading our links and platforms are a bit more tricky. First, we’ll copy over our primary id from our main table, then iterate over each platform and link individually. # Get article id and copy to platforms & links tablesarticle_id = db. execute(“SELECT id FROM articles WHERE title =? ”, (title, ))for item in article_id: _id = item[0]for i, _ in enumerate(platform): db. execute(f”UPDATE platforms SET platform{i} =? WHERE article_id =? ”, (platform[i], _id))for i, _ in enumerate(links): db. execute(f”UPDATE links SET link{i} =? WHERE article_id =? ”, (links[i], _id))# Commit ()The last step here is to commit all these changes to the database. With that done, our email parser is complete! If you’d like, you can use something like DB Browser to check that the contents of your database have been successfully ewing database with DB BrowserIn case you need it, I’ve uploaded the full code for this on my website and Github.

Frequently Asked Questions about python parse html email

Leave a Reply

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