When I was asked to use a distributed task queue for emails on a Django project, I chose
django-celery-email. However, during developing and testing, I faced some problems due to the lack
of clear guide from django-celery-email, so I wrote this post as a step by step guide for anyone
who wants use it with much ease. So let’s get started!
By following http://12factor.net/config, we should export the required variables. For development
convenience, .env file is supported and recommeded only for development mode. So let’s create .env
file at django-celery/.env with the following content:
ADMINS variable is used for testing emails, you should fill in your admins details.
Run the Django application:
12
$ ./manage.py migrate # migrate for the first time to create db schema creation and migration
$ ./manage.py runserver 0.0.0.0:8000
You should see something like this:
12345678
(django-celery)vagrant@vagrant:~/workspace/personal/django-celery$ ./manage.py runserver 0.0.0.0:8000
Performing system checks...
System check identified no issues (0 silenced).
December 01, 2015 - 13:09:11
Django version 1.8.7, using settings 'settings.project.dev'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
Open http://localhost:8000, you should see the 404 error page and it’s expected. We’ll add
functionalities for the application by next steps.
Heroku Deployment
Let’s deploy the Django application on Heroku to apply continuous delivery philosophy.
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
Subject: Your signup at localhost.
From: webmaster@localhost
To: sample.user@gmail.com
Date: Mon, 21 Dec 2015 11:02:30 -0000
Message-ID: <20151221110230.23463.80845@vagrant.vm>
Dear hoatle,
Thank you for signing up at localhost.
To activate your account you should click on the link below:
http://localhost:8000/accounts/activate/fe547230a3039c476a127408e9d824894d0a9064/
Thanks for using our site!
Sincerely,
localhost
-------------------------------------------------------------------------------
To deploy Heroku:
Note: we need to set SITE_DOMAIN and SITE_NAME to match the created Heroku application.
These variables are already configured by django-boilerplate by default on development mode.
You should see the page of https://<your_app_name>.herokuapp.com/accounts/signup now. However, don’t
try to signup on the Heroku app yet because we need to configure the email backend.
SMTP Email Backend Setup
By default, development mode uses console backend and production mode uses SMTP backend for emails.
Let’s use SMTP backend for both development mode on localhost and production mode on Heroku.
We see that MAILGUN_XXX variables are provided, we will use it on development
mode by adding the following lines into the .env file from the config content of your app
environment:
$ ./manage.py shell
Python 2.7.6 (default, Apr 15 2015, 20:14:49)
Type "copyright", "credits" or "license" for more information.
IPython 4.0.1 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: from django.core import mail
In [2]: mail.mail_admins('test', 'test')
In [3]:
You need to check your mailbox to see that a test email should be sent to you.
Now you could signup and receive email at: https://<your_app_name>.herokuapp.com/accounts/signup/
To start Celery app: $ ./scripts/celery.sh, and you should see the following content:
12345678910111213141516171819202122232425262728
-------------- celery@vagrant v3.1.19 (Cipater)
---- **** -----
--- * *** * -- Linux-3.13.0-49-generic-x86_64-with-debian-wheezy-sid
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: Project:0x2f9a710
- ** ---------- .> transport: amqp://ssnipivn:**@jaguar.rmq.cloudamqp.com:5672/ssnipivn
- ** ---------- .> results: disabled
- *** --- * --- .> concurrency: 2 (prefork)
-- ******* ----
--- ***** ----- [queues]
-------------- .> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send_multiple
[2015-12-21 12:13:22,788: INFO/Beat] beat: Starting...
[2015-12-21 12:13:24,532: INFO/MainProcess] Connected to amqp://ssnipivn:**@jaguar.rmq.cloudamqp.com:5672/ssnipivn
[2015-12-21 12:13:26,851: INFO/MainProcess] mingle: searching for neighbors
[2015-12-21 12:13:31,216: INFO/MainProcess] mingle: all alone
/home/vagrant/.virtualenvs/django-celery/lib/python2.7/site-packages/celery/fixups/django.py:265: UserWarning: Using settings.DEBUG leads to a memory leak, never use this setting in production environments!
warnings.warn('Using settings.DEBUG leads to a memory leak, never '
[2015-12-21 12:13:36,019: WARNING/MainProcess] /home/vagrant/.virtualenvs/django-celery/lib/python2.7/site-packages/celery/fixups/django.py:265: UserWarning: Using settings.DEBUG leads to a memory leak, never use this setting in production environments!
warnings.warn('Using settings.DEBUG leads to a memory leak, never '
[2015-12-21 12:13:36,023: WARNING/MainProcess] celery@vagrant ready.
After that, sending test email to admins should work without any blocking by opening a new terminal
window:
123456789101112131415161718
$ vagrant ssh
$ ws
$ cd personal/django-celery
$ workon django-celery
$ ./manage.py shell
Python 2.7.6 (default, Apr 15 2015, 20:14:49)
Type "copyright", "credits" or "license" for more information.
IPython 4.0.1 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: from django.core import mail
In [2]: mail.mail_admins('test', 'test')
That’s it. We’re done on development mode. Let’s deploy on Heroku with:
2015-12-21T12:30:35.946701+00:00 heroku[celery.1]: Starting process with command `scripts/celery.sh`
2015-12-21T12:30:37.616409+00:00 app[celery.1]: /app/.heroku/python/lib/python2.7/site-packages/dotenv.py:53: UserWarning: Not reading /app/.env - it doesn't exist.
2015-12-21T12:30:37.616419+00:00 app[celery.1]: warnings.warn("Not reading {0} - it doesn't exist.".format(dotenv))
2015-12-21T12:30:38.278350+00:00 app[celery.1]: [2015-12-21 12:30:38,278: INFO/MainProcess] Connected to amqp://ssnipivn:**@jaguar.rmq.cloudamqp.com:5672/ssnipivn
2015-12-21T12:30:38.220898+00:00 app[celery.1]: [2015-12-21 12:30:38,220: WARNING/MainProcess] /app/.heroku/python/lib/python2.7/site-packages/celery/apps/worker.py:161: CDeprecationWarning:
2015-12-21T12:30:38.220902+00:00 app[celery.1]: Starting from version 3.2 Celery will refuse to accept pickle by default.
2015-12-21T12:30:38.220904+00:00 app[celery.1]: The pickle serializer is a security concern as it may give attackers
2015-12-21T12:30:38.220903+00:00 app[celery.1]:
2015-12-21T12:30:38.220905+00:00 app[celery.1]: the ability to execute any command. It's important to secure
2015-12-21T12:30:38.220908+00:00 app[celery.1]: the default choice.
2015-12-21T12:30:38.220907+00:00 app[celery.1]: that enabling pickle should require a deliberate action and not be
2015-12-21T12:30:38.220906+00:00 app[celery.1]: your broker from unauthorized access when using pickle, so we think
2015-12-21T12:30:38.220909+00:00 app[celery.1]:
2015-12-21T12:30:38.220910+00:00 app[celery.1]: If you depend on pickle then you should set a setting to disable this
2015-12-21T12:30:38.220910+00:00 app[celery.1]: warning and to be sure that everything will continue working
2015-12-21T12:30:38.220914+00:00 app[celery.1]: You must only enable the serializers that you will actually use.
2015-12-21T12:30:38.220913+00:00 app[celery.1]: CELERY_ACCEPT_CONTENT = ['pickle', 'json', 'msgpack', 'yaml']
2015-12-21T12:30:38.220912+00:00 app[celery.1]:
2015-12-21T12:30:38.220915+00:00 app[celery.1]:
2015-12-21T12:30:38.220913+00:00 app[celery.1]:
2015-12-21T12:30:38.220915+00:00 app[celery.1]:
2015-12-21T12:30:38.220911+00:00 app[celery.1]: when you upgrade to Celery 3.2::
2015-12-21T12:30:38.220917+00:00 app[celery.1]:
2015-12-21T12:30:38.223101+00:00 app[celery.1]: ---- **** -----
2015-12-21T12:30:38.220916+00:00 app[celery.1]: warnings.warn(CDeprecationWarning(W_PICKLE_DEPRECATED))
2015-12-21T12:30:38.223104+00:00 app[celery.1]: - ** ---------- .> app: Project:0x7f590f5fad10
2015-12-21T12:30:38.223107+00:00 app[celery.1]: --- ***** ----- [queues]
2015-12-21T12:30:38.223111+00:00 app[celery.1]: . djcelery_email_send_multiple
2015-12-21T12:30:38.223102+00:00 app[celery.1]: --- * *** * -- Linux-3.13.0-66-generic-x86_64-with-debian-jessie-sid
2015-12-21T12:30:38.262153+00:00 app[celery.1]: [2015-12-21 12:30:38,261: INFO/Beat] beat: Starting...
2015-12-21T12:30:38.223098+00:00 app[celery.1]:
2015-12-21T12:30:38.301313+00:00 app[celery.1]: [2015-12-21 12:30:38,301: INFO/MainProcess] mingle: searching for neighbors
2015-12-21T12:30:38.223105+00:00 app[celery.1]: - ** ---------- .> results: disabled
2015-12-21T12:30:38.223109+00:00 app[celery.1]:
2015-12-21T12:30:38.223100+00:00 app[celery.1]: -------------- celery@91af8d04-4b15-482e-937b-0f9a49a0eff7 v3.1.19 (Cipater)
2015-12-21T12:30:38.223102+00:00 app[celery.1]: -- * - **** ---
2015-12-21T12:30:38.223106+00:00 app[celery.1]: - *** --- * --- .> concurrency: 8 (prefork)
2015-12-21T12:30:38.223109+00:00 app[celery.1]:
2015-12-21T12:30:38.223103+00:00 app[celery.1]: - ** ---------- [config]
2015-12-21T12:30:38.223106+00:00 app[celery.1]: -- ******* ----
2015-12-21T12:30:38.223110+00:00 app[celery.1]: [tasks]
2015-12-21T12:30:38.223104+00:00 app[celery.1]: - ** ---------- .> transport: amqp://ssnipivn:**@jaguar.rmq.cloudamqp.com:5672/ssnipivn
2015-12-21T12:30:38.223108+00:00 app[celery.1]: -------------- .> celery exchange=celery(direct) key=celery
2015-12-21T12:30:38.223111+00:00 app[celery.1]:
2015-12-21T12:30:39.322701+00:00 app[celery.1]: [2015-12-21 12:30:39,322: INFO/MainProcess] mingle: all alone
2015-12-21T12:30:39.352403+00:00 app[celery.1]: [2015-12-21 12:30:39,352: WARNING/MainProcess] celery@91af8d04-4b15-482e-937b-0f9a49a0eff7 ready.
2015-12-21T12:30:36.537615+00:00 heroku[celery.1]: State changed from starting to up
You could try sending test emails to admins with:
12345678910
$ heroku run python manage.py shell
Running python manage.py shell on dj-celery... up, run.9412
/app/.heroku/python/lib/python2.7/site-packages/dotenv.py:53: UserWarning: Not reading /app/.env - it doesn't exist.
warnings.warn("Not reading {0} - it doesn't exist.".format(dotenv))
Python 2.7.10 (default, May 27 2015, 20:38:41)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.core import mail
>>> mail.mail_admins('test', 'test')
In this post, I’ve guided you step by step to setup Celery as a distributed task queue for emails
on Django projects. It’s very easy to set everything up thanks to the django-boilerplate project.
If you need any Django consultant or Django development, don’t hesitate to contact us at:
hq@teracy.com and we’re very eager to work with you on Django, Python projects.