Analyse hops taken by an Email to reach you. Get structured information about each hop - Hostname, Protocol used, Timestamp, and Delay.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.


Travis branch PRs Welcome

Analyse hops taken by an Email to reach you. Get structured information about each hop - Hostnames, Protocol used, Timestamp, and Delay.

Only tested with Python 2.7

In your project: pip install emailtrail or if you use pipenv like me pipenv install emailtrail

Table of Contents


We can analyse an email source or raw headers

email = """
Received: by with SMTP id b200csp1430876ywa;
        Tue, 10 Oct 2017 01:17:02 -0700 (PDT)
X-Received: by with SMTP id b20mr6116862vke.110.1507623422746;
        Tue, 10 Oct 2017 01:17:02 -0700 (PDT)
Received: from ( [])
        by with SMTPS id b31sor1345013uaa.124.2017.
        for <>
        (Google Transport Security);
        Tue, 10 Oct 2017 01:17:02 -0700 (PDT)
Received-SPF: pass ( domain of designates as permitted sender) client-ip=;
X-Received: by with SMTP id w4mr6874179uaa.75.1507623422198; Tue, 10 Oct 2017 01:17:02 -0700 (PDT)
MIME-Version: 1.0
Received: by with HTTP; Tue, 10 Oct 2017 01:17:01 -0700 (PDT)
From: Mr. Money Bags <>
Date: Tue, 10 Oct 2017 01:17:01 -0700
Content-Type: text/plain; charset="UTF-8"

A business opportunity awaits

Lets analyse it

import emailtrail
  'To': u';',
  'From': u'Mr. Money Bags <>',
  'Bcc': u'',
  'Cc': u'None',
  'total_delay': 1,
  'trail': [
      'delay': 0,
      'from': '',
      'protocol': 'HTTP',
      'receivedBy': '',
      'timestamp': 1507623421
      'delay': 1,
      'from': '',
      'protocol': 'SMTPS',
      'receivedBy': '',
      'timestamp': 1507623422
      'delay': 0,
      'from': '',
      'protocol': 'SMTP',
      'receivedBy': '',
      'timestamp': 1507623422

The analyse function returns a python dictionary. The trail shows the email hops sorted in chronological order. Each intermediary email server adds a Received header to the mail, from which the module parses the following information:

  • protocol : e.g HTTP, SMTP etc.
  • from : The name the sending computer gave for itself
  • receivedBy: The receiving computers name
  • timestamp : Unix epoch

An empty string value is set for fields which couldn't be determined.

  • delay: The delay (in seconds) is computed by taking the difference of two consecutive hops. In above example there was a delay of 1 sec from to

Analysing a single Received header

>>> header = """from ( [2607:f8b0:400c:c05::233])\n        by with ESMTPS id d124si110912930vka.142.2016.\n        for <>\n        (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n        Wed, 16 Dec 2015 16:34:34 -0600 """

>>> from emailtrail import analyse_hop, extract_protocol, extract_from_label, extract_received_by_label, extract_timestamp

>>> extract_protocol(header)

>>> extract_from_label(header)

>>> extract_received_by_label(header)

>>> extract_timestamp(header)

>>> analyse_hop(header)
    "from": "",
    "receivedBy": "",
    "protocol": "ESMTPS",
    "timestamp": 1450305274


  • Sometimes during delay calculation the timestamp difference may be negative. It's not possible for a server to recieve the email before previous one, It means that either one or both of the servers clocks are off. We assume a delay of 0 for this hop.


emailtrail uses pipenv for managing virtual env and package versions.

  • Fork the repo and clone it.
  • In project root: pipenv install --dev --two. This installs packages required for testing and linting
  • Jump into your virutal env: pipenv shell
  • Running tests: pytest
  • If you want to understand the code, read the test cases first.
  • Make your changes -> Pass the tests -> Push to your branch -> Create pull request -> Profit ??


In the middle of developing this module, I switched to TDD. Albeit slow for a first timer initially, It proved to be a very effective approach later on.

  • Forces you to think how to structure your code.
  • Less coupling, small functions with minimal to none side effects, well defined interfaces.
  • Confidence in refactoring code quickly. (Everyone loves it when their investments pay off)