{ "info": { "author": "Resulto Dev Team", "author_email": "dev@resulto.ca", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Communications :: Email", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "pytracking - Email Open and Click Tracking Library\n==================================================\n\n:Authors:\n Resulto Developpement Web Inc.\n:Version: 0.2.0\n\nThis library provides a set of functions that provide open and click tracking\nwhen sending emails. This is particularly useful if you rely on an Email\nService Provider (ESP) such as Amazon SES or PostmarkApp that does not provide\nopen and click tracking.\n\nThe library only provides building blocks and does not handle the actual\nsending of email or the serving of tracking pixel and links, but it comes\npretty close to this.\n\n.. image:: https://img.shields.io/circleci/project/github/resulto/pytracking.svg\n :target: https://circleci.com/gh/resulto-admin/pytracking\n\n.. image:: https://img.shields.io/pypi/v/pytracking.svg\n :target: https://pypi.python.org/pypi/pytracking\n\n.. image:: https://img.shields.io/pypi/l/pytracking.svg\n\n.. image:: https://img.shields.io/pypi/pyversions/pytracking.svg\n\n\n.. contents:: Summary\n :backlinks: entry\n :local:\n\n\nOverview\n--------\n\nThere are two main steps when tracking email opens and link clicks:\n\n1. Adding tracking information to emails\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo track email opens, the generally accepted strategy is to add a small 1x1\ntransparent pixel at the end of an email. When a user opens an email, the email\nclient (e.g., gmail, outlook, thunderbird) will load the pixel by making a GET\nrequest. The web server serving the request will then record the open and\nnotify the sender of the email.\n\nTo track link clicks, the generally accepted strategy is to rewrite links in an\nemail to change the destination to a proxy. Once a user clicks on the link, the\nproxy redirects the user to the real link and notifies the sender of the email.\n\npytracking provides a stateless strategy to open and click tracking: all the\ninformation you want to track are encoded in the pixel (open) and proxy (click)\nURLs. For example, if you want to track the customer id and the transaction id\nassociated with a particular email, pytracking will encode this information in\nthe URL. When the user opens the email or clicks on a link, the customer id and\ntransaction id will be decoded and can then be sent to a webhook.\n\nSee the `Get Open Tracking Link`_ section for a quick example.\n\n\n2. Handling email opens and link clicks\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOnce a user opens an email or clicks on a link, the email client will send a\nrequest to the encoded URL. Your web server will receive such request and pass\nit to pytracking, which will decode the tracking information. You can then use\nthe tracking information directly (e.g., update your tracking database) or you\ncan send the information to a webhook.\n\nIn the case of link tracking, the decoded information will contain the original\nURL that you must redirect the email client to.\n\nSee the `Get Open Tracking Data from URL`_ section for a quick example.\n\n\n\nOptional Major Features provided by pytracking\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n1. Encryption: pytracking uses base 64 to encode your tracking information,\n which can be decoded by anyone. You can optionaly encrypt your tracking\n information, which can only be decoded if you have the key. See the\n `Encrypting Data`_ section for more information.\n\n2. HTML modification: pytracking can modify an HTML email to replace all links\n and add a tracking pixel. See the `Modifying HTML emails to add tracking\n links`_ section.\n\n3. Django: if you use Django to serve open and click tracking URLs, you can\n extend pytracking Django views, which already provides the redirect and\n pixel serving. See the `Using pytracking with Django`_ section.\n\n4. Webhooks: pytracking offers a shortcut function to make a POST request to a\n webhook. See the `Notifying Webhooks`_ section.\n\n\nRequirements\n------------\n\npytracking works with Python 3.4+. It doesn't require any external library, but\nthere are many optional features that have dependencies.\n\n\nInstallation\n------------\n\nYou can install pytracking using pip:\n\n::\n\n pip install pytracking\n\nYou can install specific features with extras:\n\n::\n\n pip install pytracking[django,crypto]\n\nYou can also install all features:\n\n::\n\n pip install pytracking[all]\n\n\n\nBasic Library Usage\n-------------------\n\nYou can generate two kinds of tracking links with pytracking: a link to a\ntransparent tracking pixel and a link that redirects to another link.\n\nEncoding\n~~~~~~~~\n\nYou can encode metadata in both kinds of links. For example, you can associate\na customer id with a click tracking link so when the customer clicks on the\nlink, you'll know exactly which customer clicked on it.\n\npylinktracking implements a stateless tracking strategy: all necessary\ninformation can be encoded in the tracking links. You can optionally keep\ncommon settings (e.g., default metadata to associate with all links, webhook\nURL) in a separate configuration.\n\nThe information is encoded using url-safe base64 so anyone intercepting your\nlinks, including your customers, could potentially decode the information. You\ncan optionally encrypt the tracking information (see below).\n\nMost functions take as a parameter a ``pytracking.Configuration``\ninstance that tells how to generate the links. You can also pass the\nconfiguration parameters as ``**kwargs`` argument or can mix both: the kwargs\nwill override the configuration parameters.\n\nDecoding\n~~~~~~~~\n\nOnce you get a request from a tracking link, you can use pytracking to decode\nthe link and get a ``pytracking.TrackingResult`` instance, which contains\ninformation such as the link to redirect to (if it's a click tracking link),\nthe associated metadata, the webhook URL to notify, etc.\n\nBasic Library Examples\n----------------------\n\nGet Open Tracking Link\n~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n import pytracking\n\n open_tracking_url = pytracking.get_open_tracking_url(\n {\"customer_id\": 1}, base_open_tracking_url=\"https://trackingdomain.com/path/\",\n webhook_url=\"http://requestb.in/123\", include_webhook_url=True)\n\n # This will produce a URL such as:\n # https://trackingdomain.com/path/e30203jhd9239754jh21387293jhf989sda=\n\n\nGet Open Tracking Link with Configuration\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n import pytracking\n\n configuration = pytracking.Configuration(\n base_open_tracking_url=\"https://trackingdomain.com/path/\",\n webhook_url=\"http://requestb.in/123\",\n include_webhook_url=False)\n\n open_tracking_url = pytracking.get_open_tracking_url(\n {\"customer_id\": 1}, configuration=configuration)\n\n # This will produce a URL such as:\n # https://trackingdomain.com/path/e30203jhd9239754jh21387293jhf989sda=\n\n\nGet Click Tracking Link\n~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n import pytracking\n\n click_tracking_url = pytracking.get_click_tracking_url(\n \"http://www.example.com/?query=value\", {\"customer_id\": 1},\n base_click_tracking_url=\"https://trackingdomain.com/path/\",\n webhook_url=\"http://requestb.in/123\", include_webhook_url=True)\n\n # This will produce a URL such as:\n # https://trackingdomain.com/path/e30203jhd9239754jh21387293jhf989sda=\n\n\nGet Open Tracking Data from URL\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n import pytracking\n\n full_url = \"https://trackingdomain.com/path/e30203jhd9239754jh21387293jhf989sda=\"\n tracking_result = pytracking.get_open_tracking_result(\n full_url, base_open_tracking_url=\"https://trackingdomain.com/path/\")\n\n # Metadata is in tracking_result.metadata\n # Webhook URL is in tracking_result.webhook_url\n\n\nGet Click Tracking Data from URL\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n import pytracking\n\n full_url = \"https://trackingdomain.com/path/e30203jhd9239754jh21387293jhf989sda=\"\n tracking_result = pytracking.get_open_tracking_result(\n full_url, base_click_tracking_url=\"https://trackingdomain.com/path/\")\n\n # Metadata is in tracking_result.metadata\n # Webhook URL is in tracking_result.webhook_url\n # Tracked URL to redirect to is in tracking_result.tracked_url\n\n\nGet a 1x1 transparent PNG pixel\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n import pytracking\n\n (pixel_byte_string, mime_type) = pytracking.get_open_tracking_pixel()\n\n\n\nEncrypting Data\n---------------\n\nYou can encrypt your encoded data to prevent third parties from accessing the\ntracking data encoded in your link.\n\nTo use the encryption feature, you must install pytracking with\n``pytracking[crypto]``, which uses the `cryptography Python library\n`_.\n\nEncrypting your data slightly increases the length of the generated URL.\n\n::\n\n import pytracking\n from cryptography.fernet import Fernet\n\n key = Fernet.generate_key()\n\n # Encode\n click_tracking_url = pytracking.get_click_tracking_url(\n \"http://www.example.com/?query=value\", {\"customer_id\": 1},\n base_click_tracking_url=\"https://trackingdomain.com/path/\",\n webhook_url=\"http://requestb.in/123\", include_webhook_url=True,\n encryption_bytestring_key=key)\n\n # Decode\n tracking_result = pytracking.get_open_tracking_result(\n full_url, base_click_tracking_url=\"https://trackingdomain.com/path/\",\n encryption_bytestring_key=key)\n\n\nUsing pytracking with Django\n----------------------------\n\npytracking comes with View classes that you can extend and that handle open and\nclick tracking link request.\n\nFor example, the ``pytracking.django.OpenTrackingView`` will return a 1x1\ntransparent PNG pixel for GET requests. The\n``pytracking.django.ClickTrackingView`` will return a 302 redirect response to\nthe tracked URL.\n\nBoth views will return a 404 response if the tracking URL is invalid. Both\nviews will capture the user agent and the user ip of the request. This\ninformation will be available in TrackingResult.request_data.\n\nYou can extend both views to determine what to do with the tracking result\n(e.g., call a webhook or submit a task to a celery queue). Finally, you can\nencode your configuration parameters in your Django settings or you can compute\nthem in your view.\n\nTo use the django feature, you must install pytracking with\n``pytracking[django]``.\n\nConfiguration parameters in Django settings\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nYou can provide default configuration parameters in your Django settings by\nadding this key in your settings file:\n\n::\n\n PYTRACKING_CONFIGURATION = {\n \"webhook_url\": \"http://requestb.in/123\",\n \"base_open_tracking_url\": \"http://tracking.domain.com/open/\",\n \"base_click_tracking_url\": \"http://tracking.domain.com/click/\",\n \"default_metadata\": {\"analytics_key\": \"123456\"}\n }\n\n\nExtending default views\n~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n from pytracking import Configuration\n from pytracking.django import OpenTrackingView, ClickTrackingView\n\n class MyOpenTrackingView(OpenTrackingView):\n\n def notify_tracking_event(self, tracking_result):\n # Override this method to do something with the tracking result.\n # tracking_result.request_data[\"user_agent\"] and\n # tracking_result.request_data[\"user_ip\"] contains the user agent\n # and ip of the client.\n send_tracking_result_to_queue(tracking_result)\n\n def notify_decoding_error(self, exception):\n # Called when the tracking link cannot be decoded\n # Override this to, for example, log the exception\n logger.log(exception)\n\n def get_configuration(self):\n # By defaut, fetchs the configuration parameters from the Django\n # settings. You can return your own Configuration object here if\n # you do not want to use Django settings.\n return Configuration()\n\n\n class MyClickTrackingView(ClickTrackingView):\n\n def notify_tracking_event(self, tracking_result):\n # Override this method to do something with the tracking result.\n # tracking_result.request_data[\"user_agent\"] and\n # tracking_result.request_data[\"user_ip\"] contains the user agent\n # and ip of the client.\n send_tracking_result_to_queue(tracking_result)\n\n def notify_decoding_error(self, exception):\n # Called when the tracking link cannot be decoded\n # Override this to, for example, log the exception\n logger.log(exception)\n\n def get_configuration(self):\n # By defaut, fetchs the configuration parameters from the Django\n # settings. You can return your own Configuration object here if\n # you do not want to use Django settings.\n return Configuration()\n\nURLs configuration\n~~~~~~~~~~~~~~~~~~\n\nAdd this to your urls.py file:\n\n::\n\n urlpatterns = [\n url(\n \"^open/(?P[\\w=-]+)/$\", MyOpenTrackingView.as_view(),\n name=\"open_tracking\"),\n url(\n \"^click/(?P[\\w=-]+)/$\", MyClickTrackingView.as_view(),\n name=\"click_tracking\"),\n ]\n\n\nNotifying Webhooks\n------------------\n\nYou can send a POST request to a webhook with the tracking result. The webhook\nfeature just packages the tracking result as a json string in the POST body. It\nalso sets the content encoding to ``application/json``.\n\nTo use the webhook feature, you must install pytracking with\n``pytracking[webhook]``.\n\n\n::\n\n import pytracking\n from pytracking.webhook import send_webhook\n\n # Assumes that the webhook url is encoded in the url.\n full_url = \"https://trackingdomain.com/path/e30203jhd9239754jh21387293jhf989sda=\"\n tracking_result = pytracking.get_open_tracking_result(\n full_url, base_click_tracking_url=\"https://trackingdomain.com/path/\")\n\n # Will send a POST request with the following json str body:\n # {\n # \"is_open_tracking\": False,\n # \"is_click_tracking\": True,\n # \"metadata\": {...},\n # \"request_data\": None,\n # \"tracked_url\": \"http://...\",\n # \"timestamp\": 1389177318\n # }\n send_webhook(tracking_result)\n\n\n\nModifying HTML emails to add tracking links\n-------------------------------------------\n\nIf you have an HTML email, pytracking can update all links with tracking links\nand it can also add a transparent tracking pixel at the end of your email.\n\nTo use the HTML feature, you must install pytracking with ``pytracking[html]``,\nwhich uses the `lxml library `_.\n\n::\n\n import pytracking\n from pytracking.html import adapt_html\n\n html_email_text = \"...\"\n new_html_email_text = adapt_html(\n html_email_text, extra_metadata={\"customer_id\": 1},\n click_tracking=True, open_tracking=True)\n\n\nTesting pytracking\n------------------\n\npytracking uses `tox `_ and `py.test\n`_. If you have tox installed, just run\n``tox`` and all possible configurations of pytracking will be tested on Python\n3.4.\n\n\nTODO\n----\n\n1. Add various checks to ensure that the input data is sane and does not bust\n any known limits (e.g., URL length).\n\n2. Add more examples.\n\n3. Allow mulitple webhooks and webhooks per tracking method.\n\n4. Transform Django views into view mixins.\n\n5. Add option to encode the webhook timeout in the tracking URL.\n\n6. Document caveats of using pytracking.html (example: long emails are often\n cut off by the email clients and the tracking pixel is thus not loaded).\n\n7. Add some form of API documentation (at least Configuration and\n TrackingResult), maybe as a separate document.\n\nLicense\n-------\n\nThis software is licensed under the `New BSD License`. See the `LICENSE` file\nin the repository for the full license text.\n\nProfessional Support and Services\n---------------------------------\n\nIf you need professional support for pytracking, you want a bug to be quickly\nfixed or you want a feature request to be quickly implemented, Resulto can\nprovide such service. Just drop us a line at `pytracking@resulto.ca\n`_\n\n\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/resulto-admin/pytracking", "keywords": "email open click tracking", "license": "New BSD", "maintainer": "", "maintainer_email": "", "name": "pytracking", "package_url": "https://pypi.org/project/pytracking/", "platform": "", "project_url": "https://pypi.org/project/pytracking/", "project_urls": { "Homepage": "https://github.com/resulto-admin/pytracking" }, "release_url": "https://pypi.org/project/pytracking/0.2.0/", "requires_dist": [ "cryptography (>=1.4); extra == 'all'", "django (>=1.7); extra == 'all'", "django-ipware (>=1.1.5); extra == 'all'", "lxml (>=3.6.1); extra == 'all'", "pytest (>=2.9.2); extra == 'all'", "requests (>=2.10.0); extra == 'all'", "tox (>=2.3.1); extra == 'all'", "cryptography (>=1.4); extra == 'crypto'", "django (>=1.7); extra == 'django'", "django-ipware (>=1.1.5); extra == 'django'", "lxml (>=3.6.1); extra == 'html'", "pytest (>=2.9.2); extra == 'test'", "tox (>=2.3.1); extra == 'test'", "requests (>=2.10.0); extra == 'webhook'" ], "requires_python": "", "summary": "Email open and click tracking", "version": "0.2.0" }, "last_serial": 2928716, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "e82346cbeb8833e2d0c8db6311ee9695", "sha256": "9969801fb4bf8fc9a4fd4976de3f1255da765ae62fb108bf67b9a244f3431290" }, "downloads": -1, "filename": "pytracking-0.1.0-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "e82346cbeb8833e2d0c8db6311ee9695", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 17795, "upload_time": "2016-08-10T14:57:43", "url": "https://files.pythonhosted.org/packages/ba/2b/316ecd798ff0ffe4a3766ea2426a1fd42fb52b7e82dba7a0b9b8a9797c7c/pytracking-0.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2b0d62e925b1cb108b9cdc6edc55d019", "sha256": "75b01ad64c95c13816787cafc831f869c76b851cbf3795715286d81096a77254" }, "downloads": -1, "filename": "pytracking-0.1.0.tar.gz", "has_sig": true, "md5_digest": "2b0d62e925b1cb108b9cdc6edc55d019", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17619, "upload_time": "2016-08-10T14:57:46", "url": "https://files.pythonhosted.org/packages/e9/0c/4687ef47b55b745605a9fdc70955abb0731af580cba5fd49fb10b7dd7c58/pytracking-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "dce2b6d50d0e5a87858305cbead1e0af", "sha256": "6c15c9560c25c5f8e05b8308aec2d4f941b7d37bc72fb0f7a4155dbdc879881b" }, "downloads": -1, "filename": "pytracking-0.2.0-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "dce2b6d50d0e5a87858305cbead1e0af", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18254, "upload_time": "2017-06-06T09:38:06", "url": "https://files.pythonhosted.org/packages/2f/34/d9ab65db98e7740815795d45c8eaf57c58ef4b741368151b422eec2376d4/pytracking-0.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7be969348afd3bf91d2ac8506d3732da", "sha256": "67f8a795c4dbcfc816a655aa11d3e0e72bc79d82357d5a725fd4fb220e35c9e9" }, "downloads": -1, "filename": "pytracking-0.2.0.tar.gz", "has_sig": true, "md5_digest": "7be969348afd3bf91d2ac8506d3732da", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18154, "upload_time": "2017-06-06T09:38:07", "url": "https://files.pythonhosted.org/packages/0c/8f/4c6cf1dacfa3067554606596ad463d76a0d80b4be9b68d8a7792d535e947/pytracking-0.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "dce2b6d50d0e5a87858305cbead1e0af", "sha256": "6c15c9560c25c5f8e05b8308aec2d4f941b7d37bc72fb0f7a4155dbdc879881b" }, "downloads": -1, "filename": "pytracking-0.2.0-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "dce2b6d50d0e5a87858305cbead1e0af", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18254, "upload_time": "2017-06-06T09:38:06", "url": "https://files.pythonhosted.org/packages/2f/34/d9ab65db98e7740815795d45c8eaf57c58ef4b741368151b422eec2376d4/pytracking-0.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7be969348afd3bf91d2ac8506d3732da", "sha256": "67f8a795c4dbcfc816a655aa11d3e0e72bc79d82357d5a725fd4fb220e35c9e9" }, "downloads": -1, "filename": "pytracking-0.2.0.tar.gz", "has_sig": true, "md5_digest": "7be969348afd3bf91d2ac8506d3732da", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18154, "upload_time": "2017-06-06T09:38:07", "url": "https://files.pythonhosted.org/packages/0c/8f/4c6cf1dacfa3067554606596ad463d76a0d80b4be9b68d8a7792d535e947/pytracking-0.2.0.tar.gz" } ] }