Best answer

Parse Email Reply / Extract last message only

  • 27 May 2020
  • 4 replies

Userlevel 2

I'm looking at parsing out just the most recent reply/message from an email thread as part of a zap.

I've found this link but how to I use it within a Zap?

i.e. when I pick up a thread from gmail how do I just extract the most recent message?

Is this possible in Code by Zapier and if so how?



Yes that is fine, I will email you in the morning.

On Fri, Nov 16, 2012 at 1:48 PM, Zapier wrote:

Our support team just commented on your open Ticket: "Hi Royce, can we chat in the morning about your question?"

Ouput: i.e. the parsed email:

Yes that is fine, I will email you in the morning.


Best answer by ikbelkirasan 6 June 2020, 14:58

@Liz_Roberts - Thanks for the mention! I’ll try and help :)

@taylornd Try using the code snippet from this gist to extract the reply fragment.


View original

This post has been closed for comments. Please create a new post if you need help or have a question about this topic.

4 replies

Userlevel 7
Badge +7

Hi @taylornd ,

Thanks for reaching out! I’m tagging in one of our code gurus @ikbelkirasan to see if they may have a suggestion for you here. 

@ikbelkirasan thank you for any guidance you may be able to share!

Userlevel 7
Badge +11

@Liz_Roberts - Thanks for the mention! I’ll try and help :)

@taylornd Try using the code snippet from this gist to extract the reply fragment.


Userlevel 2

Brilliant. Thanks.

Userlevel 2

I had a go at adapting this which seemed to work as well.

email_reply_parser is a python library port of GitHub's Email Reply Parser.

For more information, visit

import re

class EmailReplyParser(object):
""" Represents a email message that is parsed.

def read(text):
""" Factory method that splits email into list of fragments

text - A string email body

Returns an EmailMessage instance
return EmailMessage(text).read()

def parse_reply(text):
""" Provides the reply portion of email.

text - A string email body

Returns reply body message

class EmailMessage(object):
""" An email message represents a parsed email body.

SIG_REGEX = re.compile(r'(--|__|-\w)|(^Sent from my (\w+\s*))')
QUOTE_HDR_REGEX = re.compile('On.*wrote:$')
QUOTED_REGEX = re.compile(r'(>+)')
HEADER_REGEX = re.compile(r'^\*?(From|Sent|To|Subject):\*? .+')
_MULTI_QUOTE_HDR_REGEX = r'(?!On.*On\s.+?wrote:)(On\s(.+?)wrote:)'

def __init__(self, text):
self.fragments = []
self.fragment = None
self.text = text.replace('\r\n', '\n')
self.found_visible = False

def read(self):
""" Creates new fragment for each line
and labels as a signature, quote, or hidden.

Returns EmailMessage instance

self.found_visible = False

is_multi_quote_header =
if is_multi_quote_header:
self.text = self.MULTI_QUOTE_HDR_REGEX.sub(is_multi_quote_header.groups()[0].replace('\n', ''), self.text)

# Fix any outlook style replies, with the reply immediately above the signature boundary line
# See email_2_2.txt for an example
self.text = re.sub('([^\n])(?=\n ?[_-])', '\\1\n', self.text, re.MULTILINE)

self.lines = self.text.split('\n')

for line in self.lines:



return self

def reply(self):
""" Captures reply message within email
reply = []
for f in self.fragments:
if not (f.hidden or f.quoted):
return '\n'.join(reply)

def _scan_line(self, line):
""" Reviews each line in email message and determines fragment type

line - a row of text from an email message
is_quote_header = self.QUOTE_HDR_REGEX.match(line) is not None
is_quoted = self.QUOTED_REGEX.match(line) is not None
is_header = is_quote_header or self.HEADER_REGEX.match(line) is not None

if self.fragment and len(line.strip()) == 0:
if self.SIG_REGEX.match(self.fragment.lines[-1].strip()):
self.fragment.signature = True

if self.fragment \
and ((self.fragment.headers == is_header and self.fragment.quoted == is_quoted) or
(self.fragment.quoted and (is_quote_header or len(line.strip()) == 0))):

self.fragment = Fragment(is_quoted, line, headers=is_header)

def quote_header(self, line):
""" Determines whether line is part of a quoted area

line - a row of the email message

Returns True or False
return self.QUOTE_HDR_REGEX.match(line[::-1]) is not None

def _finish_fragment(self):
""" Creates fragment

if self.fragment:
if self.fragment.headers:
# Regardless of what's been seen to this point, if we encounter a headers fragment,
# all the previous fragments should be marked hidden and found_visible set to False.
self.found_visible = False
for f in self.fragments:
f.hidden = True
if not self.found_visible:
if self.fragment.quoted \
or self.fragment.headers \
or self.fragment.signature \
or (len(self.fragment.content.strip()) == 0):

self.fragment.hidden = True
self.found_visible = True
self.fragment = None

class Fragment(object):
""" A Fragment is a part of
an Email Message, labeling each part.

def __init__(self, quoted, first_line, headers=False):
self.signature = False
self.headers = headers
self.hidden = False
self.quoted = quoted
self._content = None
self.lines = [first_line]

def finish(self):
""" Creates block of content with lines
belonging to fragment.
self._content = '\n'.join(self.lines)
self.lines = None

def content(self):
return self._content.strip()
return {'emailstring': EmailReplyParser.parse_reply(input_data['body'])}