Permalink
Browse files

1.0 - Initial Commit

  • Loading branch information...
paltman committed Oct 27, 2012
0 parents commit ccff15d0b736a22b41b727ef5c2003268acc137b
Showing with 563 additions and 0 deletions.
  1. +27 −0 LICENSE
  2. +8 −0 README.rst
  3. +131 −0 docs/Makefile
  4. +10 −0 docs/changelog.rst
  5. +27 −0 docs/conf.py
  6. +24 −0 docs/index.rst
  7. +35 −0 docs/installation.rst
  8. +11 −0 docs/signals.rst
  9. +98 −0 docs/usage.rst
  10. +1 −0 sendgrid_events/__init__.py
  11. +29 −0 sendgrid_events/models.py
  12. +4 −0 sendgrid_events/signals.py
  13. +7 −0 sendgrid_events/urls.py
  14. +12 −0 sendgrid_events/views.py
  15. +139 −0 setup.py
27 LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2012, Eldarion, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of Eldarion, Inc. nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,8 @@
+======================
+django-sendgrid-events
+======================
+
+a simple app to provide and endpoind for and handle batch events from
+SendGrid's Event API
+
+Documentation is online at http://django-sendgrid-events.rtfd.org
@@ -0,0 +1,131 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+PROJECT = django-sendgrid-events
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/$(PROJECT).qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/$(PROJECT).qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/$(PROJECT)"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/$(PROJECT)"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ make -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
@@ -0,0 +1,10 @@
+.. _changelog:
+
+ChangeLog
+=========
+
+
+1.0
+---
+
+- initial release
@@ -0,0 +1,27 @@
+import sys, os
+
+extensions = []
+templates_path = []
+source_suffix = '.rst'
+master_doc = 'index'
+project = u'django-sendgrid-events'
+copyright_holder = 'Eldarion, Inc'
+copyright = u'2012, %s' % copyright_holder
+exclude_patterns = ['_build']
+pygments_style = 'sphinx'
+html_theme = 'default'
+htmlhelp_basename = '%sdoc' % project
+latex_documents = [
+ ('index', '%s.tex' % project, u'%s Documentation' % project,
+ copyright_holder, 'manual'),
+]
+man_pages = [
+ ('index', project, u'%s Documentation' % project,
+ [copyright_holder], 1)
+]
+
+sys.path.insert(0, os.pardir)
+m = __import__("sendgrid_events")
+
+version = m.__version__
+release = version
@@ -0,0 +1,24 @@
+======================
+django-sendgrid-events
+======================
+
+a simple app to provide and endpoind for and handle batch events from
+SendGrid's Event API
+
+Development
+-----------
+
+The source repository can be found at https://github.com/eldarion/django-sendgrid-events
+
+
+Contents
+========
+
+.. toctree::
+ :maxdepth: 1
+
+ changelog
+ installation
+ signals
+ usage
+
@@ -0,0 +1,35 @@
+.. _installation:
+
+Installation
+============
+
+* To install ::
+
+ pip install django-sendgrid-events
+
+* Add ``'sendgrid_events'`` to your ``INSTALLED_APPS`` setting::
+
+ INSTALLED_APPS = (
+ # other apps
+ "sendgrid_events",
+ )
+
+* Add ``'sengrid_events.urls'`` as an inclusion to the your main ``urls.py``
+ file. You will likely want to provide a bit of security through obscurity
+ as you are essentially going to be trusting whatever is POSTed to this url.
+
+ You can do this by generating a UUID and then copy and pasting this as part
+ of your URL::
+
+ >>> import uuid
+ >>> print uuid.uuid4()
+ aeea4b34-e5cb-4b05-84d8-79bfee95ccf4
+
+ Then in your ``urls.py``::
+
+ url("^aeea4b34-e5cb-4b05-84d8-79bfee95ccf4/", include("sendgrid_events.urls"))
+
+* Finally, go to and setup the Events API app, pasting in the end point to this
+ url, which will be::
+
+ http(s)://<yoursite.com>/aeea4b34-e5cb-4b05-84d8-79bfee95ccf4/batch/
@@ -0,0 +1,11 @@
+.. _signals:
+
+Signals
+=======
+
+batch_processed
+---------------
+
+Provides a single argument which is the ``sendgrid_events.models.Event`` instance
+for the single event within the batch. A single batch POST can contain one or more
+events.
@@ -0,0 +1,98 @@
+.. _usage:
+
+Usage
+=====
+
+Using this after it has been setup in your site depends on what you want
+to accomplish. Just installing it will enable you to receive events on
+every email sent through your Sendgrid account.
+
+That by itself, however, likely produces much value as there is no
+context to those emails to derive any meaningful use out of.
+
+One of the cool things you can do now that you have the Events API
+configured and django-sendgrid-events hooked up, is send identifying
+data in the headers of each email you send so that when you receive
+and Event API POST you can tied each email back to some event in your
+site.
+
+To accomplish this you should make sure your email settings are
+configured to use your Sendgrid account::
+
+ EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
+ EMAIL_HOST = os.environ.get("EMAIL_HOST", "smtp.sendgrid.net")
+ EMAIL_PORT = os.environ.get("EMAIL_PORT", 587)
+ EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER", "")
+ EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD", "")
+ EMAIL_USE_TLS = True
+
+And then whenever you are sending an email in your site that you
+want to be able to track the response to send an extra header like
+so::
+
+ email = EmailMultiAlternatives(
+ "Your Subject Here",
+ "Your plain text message here",
+ "sender@email.com",
+ ["recipient@email.com"],
+ headers={
+ "X-SMTPAPI": json.dumps({
+ "unique_args": {
+ "some_key": "some_value"
+ },
+ "category": "some_category"
+ })
+ }
+ )
+ email.attach_alternative("Your html rendered email", "text/html")
+ email.send()
+
+You don't have to send HTML emails, but you can control the look a
+bit better since in order to get open and click event tracking with
+plain text emails, Sendgrids converts it to an HTML email, which
+can end up not looking how you'd like it to.
+
+Now when your events POST to the endpoint you have setup, they'll
+have this extra bit of data which you can use to link to something
+in your site. For example, say, you want to link it to the instance
+of a specific content model you can pass in as a ``unique_arg``::
+
+ "unique_args": {
+ "my_model_pk": object.pk
+ }
+
+Then hook up a signal receiver for ``sendgrid_events.signals.batch_processed``::
+
+ from django.dispatch import receiver
+
+ from sendgrid_events.signals import batch_processed
+ from mysite.myapp.models import SomeContent
+
+
+ @receiver(batch_processed)
+ def handle_batch_processed(sender, events, **kwargs):
+ for event in events:
+ try:
+ c = SomeContent.objects.get(pk=event.data.get("my_model_pk"))
+ c.email_events.create(sendgrid_event=event)
+ except SomeContent.DoesNotExist:
+ pass
+
+Where you have created a tracking model in your ``mysite.myapps.models`` for
+``SomeContent``::
+
+ class SomeContentEvent(models.Model):
+ some_content = models.ForeignKey(SomeContent, related_name="email_events")
+ sendgrid_event = models.ForeignKey(Event, related_name="+")
+
+ class Meta:
+ ordering = ["sendgrid_event__created_at"]
+
+Now, you have access to email events for that object that you can use in
+your site::
+
+ {% for event in some_content.email_events.all %}
+ <span class="label label-{{ event.kind }}" title="{{ event.created_at }}">
+ {{ event.kind }}
+ </span>
+ {% endfor %}
@@ -0,0 +1 @@
+__version__ = "1.0"
Oops, something went wrong.

0 comments on commit ccff15d

Please sign in to comment.