Use Django admin to manage drip campaign emails using querysets on Django's User model.

Related tags

Email featured
Overview

Django Drip

Build Status

Drip campaigns are pre-written sets of emails sent to customers or prospects over time. Django Drips lets you use the admin to manage drip campaign emails using querysets on Django's User model.

We wrote this specifically to scratch an itch at our startup Zapier. It currently runs all of our drip campaigns.

Read the docs or check out a demo.

Installing:

We highly recommend using pip to install django-drip, the packages are regularly updated with stable releases:

pip install django-drip

Next, you'll want to add drip to your INSTALLED_APPS in settings.py.

INSTALLED_APPS = (
    'django.contrib.contenttypes',
    'django.contrib.comments',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',

    # Your favorite apps

    'drip',
)

Don't forget to add DRIP_FROM_EMAIL to settings.py, or else we will fall back to EMAIL_HOST_USER.

Finally, be sure to run python manage.py syncdb or python manage.py migrate drip to set up the necessary database tables.

python manage.py syncdb
# or...
python manage.py migrate drip

what the admin looks like what the admin looks like for the timeline

Comments
  • Custom sender

    Custom sender

    Hey guys, I needed to send drips via SMS, so I modified django drip to make things more generic and allow custom senders. After submitting this request I realized it would probably be better to create a new migration rather than edit existing ones. Before I do that though, I want to gauge interest. Is this even a feature you want? Here is the documentation for the new feature (also added to the README). I suppose some new screenshots would also be needed.


    Custom Sender

    If you want to send messages different from the default sender (SMTP), you can create a custom sender class that inherits from SenderBase. For example:

    from drip.models import SenderBase
    
    class CustomSender(SenderBase):
        # drip is the drip.drips.DripBase object which gives access to
        # from_address and from_address_name
        def send_message(self, drip, user, subject, body, plain):
            # Custom sending logic (SMS, in app messaging, snail mail, etc.)
            ...
            # Return a boolean indicating if the message was sent or not
    

    After adding this table to the database using syncdb or a south migration, you will need to create an object of this type:

    $ python manage.py shell
    >>> from exampleapp.models import CustomSender
    >>> sender = CustomSender()
    >>> sender.name = 'My Custom Sender'
    >>> sender.save()
    

    Now when you create a Drip in the django admin you will have the option of selecting your own custom sender. When these Drips go out, django drip will send the message with your custom sender instead of the built-in method.


    opened by brad 6
  • add option to make the queryset distinct

    add option to make the queryset distinct

    I have some querysets that generate many copies of each user. This adds an option to the drip to add .distinct() at the end of the queryset. I could be wrong, but I think it should default to True.

    opened by brad 5
  • Decoupling email templates from drip

    Decoupling email templates from drip

    What do you guys think about allowing third party email content compilers to be used?

    We currently use https://github.com/bradwhittington/django-templated-email for sending emails which is great (basically, you define the email in a django template file which can extend other templates, and send the email by referencing the template's filename).

    The issue is it would make the easiest case harder probably, unless optional subject_template and body_html_template fields are left in the Drip model.

    Other, less wasteful (no optional TextFields) options:

    1. I could be to make a OneToOneField from a new model DripEmailTemplate to Drip and add it as an Inline to the Drip admin in addition to an optional "template_name" field to send to django-templated-email.
    2. It may also be harder for the easiest case, but DripEmailTemplate could be referenced from a optional ForeignKey in Drip which would allow you to have multiple Drips use the same DripEmailTemplate

    I'd be willing to take on this project but wanted to see if I could get it to work for more than just us.

    opened by sssbox 5
  • Rationale behind DRIP_FROM_EMAIL in settings.py?

    Rationale behind DRIP_FROM_EMAIL in settings.py?

    Hello Zapier,

    Great fan of your work! I am just curious as to the thought process behind the DRIP_FROM_EMAIL setting. Is there a reason why the from email is static? I figured you would want to be able to change the from email depending on the drip campaign unless I am missing a key point? Forgive me if there is something blatantly obvious.

    P.S. As per usual for github users, I would be happy to contribute code if there is interest in a non-static from email and if it abides by the wishes of the project maintainers.

    opened by sayar 5
  • Python 3 support

    Python 3 support

    Does django-drip support Python 3?

    If so, it would be nice to designate that on PyPI using classifiers in setup.py (see https://pypi.python.org/pypi?%3Aaction=list_classifiers)

    If not, what does the path forward look like?

    opened by hwkns 4
  • Bug in `drip.drips` using template source and not rendered template

    Bug in `drip.drips` using template source and not rendered template

    I apologize if I'm mistaken, but it looks like you're using the template source and not the rendrered template for the HTML version of the email body.

    See drips.drip:122

    # check if there are html tags in the rendered template if len(plain) != len(body): email.attach_alternative(self.body_template, 'text/html')

    It should reference the body local variable not self.body_template.

    bug 
    opened by kevinastone 4
  • Exclude users, i.e. support for unsubscribing

    Exclude users, i.e. support for unsubscribing

    I lack the ability to unsubscribe from the emails sent by drip. We're about to start using it for our customers, but anticipate that certain users will want to unsubscribe.

    Is this something that could be integrated with Drip, or handled separately? How do others do it?

    opened by emilisto 3
  • Various improvements

    Various improvements

    I forked budlights repository and then added the ability to use F expressions in field values.

    Bud lights comments aren't very explanatory but he has made some worthwhile improvements.

    opened by tobydeh 2
  • Use AUTH_USER_MODEL in models.

    Use AUTH_USER_MODEL in models.

    Having updated to Django 1.5 and migrated my profile information onto an extended User model, drip does not allow my app to start:

    django.core.management.base.CommandError: One or more models did not validate:
    drip.sentdrip: 'user' defines a relation with the model 'auth.User', which has been swapped out. Update the relation to point at `settings.AUTH_USER_MODEL`.
    

    May I suggest the following, in models.py:

    try:
      from settings import AUTH_USER_MODEL
    except:
      AUTH_USER_MODEL = 'auth.User'
    
    ...
    
    user = models.ForeignKey(AUTH_USER_MODEL, related_name='sent_drips')
    
    opened by SkinTeam 2
  • Support Count() aggregates for M2Ms.

    Support Count() aggregates for M2Ms.

    Use __count for a field name and then treat define the rest of the rule normally. In QuerySetRule.apply, the queryset is annotated behind the scenes and then the filter is applied.

    I wasn't sure how best to update the docs. This patch should apply cleanly to master, even though it was written against several other patches.

    opened by jsocol 2
  • namespace conflict with mock

    namespace conflict with mock

    This isn't a problem with django-drip==0.1.3, only with the latest source. Steps to reproduce:

    $ mkvirtualenv testpip
    $ pip install mock -e \
    git+https://github.com/zapier/django-drip.git#egg=django-drip
    $ python
    
    >>> from mock import patch
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ImportError: cannot import name patch
    
    opened by brad 2
  • [WIP] Modernize DRIP to run against latest Django versions.

    [WIP] Modernize DRIP to run against latest Django versions.

    • [ ] Update testing infrastructure.
      • [x] Use Tox
      • [x] Move tests out of the package.
      • [x] Lint code base.
        • [x] Run flake8 during CI.
        • [x] Run isort during CI.
      • [ ] Add coverage support.
    • [ ] Adjust Django version supports.
      • [ ] Add support for Django 1.8.
      • [ ] Drop support for Django < 1.8.
      • [ ] Add support for Django 1.8+.
    • [ ] Update documentation.
    • [ ] Release 1.0.
    opened by charettes 3
  • ManyToManyRel' object has no attribute 'parent_model

    ManyToManyRel' object has no attribute 'parent_model

    In utils.py at following line its hard to understand its like "tuple + tuple + list". fields = Model._meta.fields + Model._meta.many_to_many + Model._meta.get_all_related_objects() This is caused me error so I converted it to tuple(Model._meta.get_all_related_objects()). However now I am getting error with following traceback:

    File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\core\handlers\base.py" in get_response
      132.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
    File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\contrib\admin\options.py" in wrapper
      616.                 return self.admin_site.admin_view(view)(*args, **kwargs)
    File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\utils\decorators.py" in _wrapped_view
      110.                     response = view_func(request, *args, **kwargs)
    File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
      57.         response = view_func(request, *args, **kwargs)
    File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\contrib\admin\sites.py" in inner
      233.             return view(request, *args, **kwargs)
    File "C:\Users\Mudassar\dressikarepo\lib\site-packages\drip\admin.py" in add_view
      83.             request, extra_context=self.build_extra_context(extra_context))
    File "C:\Users\Mudassar\dressikarepo\lib\site-packages\drip\admin.py" in build_extra_context
      78.         extra_context['field_data'] = json.dumps(get_simple_fields(User))
    File "C:\Users\Mudassar\dressikarepo\lib\site-packages\drip\utils.py" in get_simple_fields
      121.     return [[f[0], f[3].__name__] for f in get_fields(Model, **kwargs)]
    File "C:\Users\Mudassar\dressikarepo\lib\site-packages\drip\utils.py" in get_fields
      98.                 RelModel = field.related.parent_model
    
    Exception Type: AttributeError at /admin/drip/drip/add/
    Exception Value: 'ManyToManyRel' object has no attribute 'parent_model'
    

    I am using djagno 1.8.5. Please advise.

    opened by MUDASSARHASHMI 1
  • Cannot Run Tests with Django 1.8.4

    Cannot Run Tests with Django 1.8.4

    I'm running Django 1.8.4 and cannot run tests. I also needed to install a forked version of django drip just to get it to run - see issue #51. I've looked through the app to try to figure out where this might be but it's beyond me.

    Trying to to run tests produces:

    Traceback (most recent call last):
      File "manage.py", line 10, in <module>
        execute_from_command_line(sys.argv)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
        utility.execute()
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 330, in execute
        self.fetch_command(subcommand).run_from_argv(self.argv)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 30, in run_from_argv
        super(Command, self).run_from_argv(argv)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/base.py", line 393, in run_from_argv
        self.execute(*args, **cmd_options)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 74, in execute
        super(Command, self).execute(*args, **options)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/base.py", line 444, in execute
        output = self.handle(*args, **options)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 90, in handle
        failures = test_runner.run_tests(test_labels)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/test/runner.py", line 210, in run_tests
        old_config = self.setup_databases()
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/test/runner.py", line 166, in setup_databases
        **kwargs
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/test/runner.py", line 370, in setup_databases
        serialize=connection.settings_dict.get("TEST", {}).get("SERIALIZE", True),
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/db/backends/base/creation.py", line 368, in create_test_db
        test_flush=not keepdb,
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 120, in call_command
        return command.execute(*args, **defaults)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/base.py", line 444, in execute
        output = self.handle(*args, **options)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 179, in handle
        created_models = self.sync_apps(connection, executor.loader.unmigrated_apps)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 318, in sync_apps
        cursor.execute(statement)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
        return self.cursor.execute(sql, params)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/db/utils.py", line 97, in __exit__
        six.reraise(dj_exc_type, dj_exc_value, traceback)
      File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 62, in execute
        return self.cursor.execute(sql)
    django.db.utils.ProgrammingError: relation "auth_user" does not exist
    
    
    opened by alexphelps 1
Owner
Zapier
Zapier
Churn Emails Inbox - Churn Emails Inbox Using Python

Churn Emails Inbox In this project, I have used the Python programming langauge

null 2 Nov 13, 2022
Envia-emails - A Python Program that creates emails

Envia-emails Os emails é algo muito importante e usado. Pensando nisso, eu criei

José Rodolfo 2 Mar 5, 2022
Django module to easily send templated emails using django templates, or using a transactional mail provider (mailchimp, silverpop, etc.)

Django-Templated-Email Info: A Django oriented templated email sending class Author: Bradley Whittington (http://github.com/bradwhittington, http://tw

Vinta Software 659 Dec 27, 2022
Pysces (read: Pisces) is a program to help you send emails with an user-customizable time-based scheduling.

Pysces (Python Scheduled-Custom-Email-Sender) Pysces (read: Pisces) is a program to help you send emails with an user-customizable time-based email se

Peter 1 Jun 16, 2022
PGP encrypted / multipart templated emails for Django

Created by Stephen McDonald Introduction django-email-extras is a Django reusable app providing the ability to send PGP encrypted and multipart emails

stephenmcd 75 May 14, 2022
Bulk send personalized emails using a .csv file and Gmail API (via EZGmail)

GSender Bulk send personalized emails using a .csv file and Gmail API (via EZGmail). Installation Install requirements.txt. Follow the EZGmail Install

null 1 Nov 23, 2021
A script based on an article I wrote on decluttering emails.

Decluttering_Email A script based on an article I wrote on decluttering emails. What does this program do? This program is a python script that sends

Ogheneyoma Obomate Okobiah 6 Oct 21, 2021
Mailrise is an SMTP server that converts the emails it receives into Apprise notifications

Mailrise is an SMTP server that converts the emails it receives into Apprise notifications. The intended use case is as an email relay for a home lab or network. By accepting ordinary email, Mailrise enables Linux servers, Internet of Things devices, surveillance systems, and outdated software to gain access to the full suite of 60+ notification services supported by Apprise, from Matrix to Nextcloud to your desktop or mobile device.

Ryan Young 293 Jan 7, 2023
Heimdall watchtower automatically sends you emails to notify you of the latest progress of your deep learning programs.

This software automatically sends you emails to notify you of the latest progress of your deep learning programs.

Zhenyue Qin 22 Dec 6, 2021
Send Emails through the terminal , fast and secure

Send Emails through the terminal , fast and secure

null 11 Aug 7, 2022
Convert emails without attachments to pdf and send as email

Email to PDF to email This script will check an imap folder for unread emails. Any unread email that does not have an attachment will be converted to

Robert Luke 21 Nov 22, 2022
A spammer to send mass emails to teachers. (Education Purposes only!)

Securly-Extension-Spammer A spammer to send mass emails to teachers. (Education Purposes only!) Setup Just go a securly blocked page(You can do this b

null 3 Jan 25, 2022
Python library for sending emails.

Mail.py Python library for sending emails. Installation git clone https://github.com/SunPodder/Mail.py cd Mail.py python setup.py install Usage Imp

Sun 3 Oct 15, 2021
Collection of emails sent from the Hungarian gov and Viktor Orbán to the citizens of Hungary

Public list of Hungary and Viktor Orbán's emails since March 2021 Collection of emails sent from the Hungarian government and Viktor Orbán to the citi

Miguel Sozinho Ramalho 1 Mar 28, 2022
A python program capable of accessing passwords associated with emails through leaked databases.

passfind A python program capable of accessing passwords associated with emails through leaked databases. A python program capable of accessing passwo

null 6 Aug 14, 2022
This Tool Is For Sending Emails From A Terminal(Termux/Kali) etc.

This is a Basic python script to send emails from a Terminal(Termux/Kali) are the only tested currently.

AnonyVox 2 Apr 4, 2022
It s a useful project for developers ... It checks available and unavailable emails

EmailChecker It s a useful project for developers ... It checks available and unavailable emails Installation : pip install EmailChecker Domains are

Sidra ELEzz 19 Jan 1, 2023
Will iterate through a list of emails on an attached csv file and email all of them a message of your choice

Email_Bot Will iterate through a list of emails on an attached csv file and email all of them a message of your choice. Before using, make sure you al

J. Brandon Walker 1 Nov 30, 2021
This python script will generate passwords for your emails, With certain lengths, And saves them into plain text files.

How to use. Change the Default length of genereated password in default.length.txt Type the email for your account. Type the website that the email an

null 2 Dec 26, 2021