} }

In course of developing any website, we need to add the email service in our projects to send messages to the customer. There are many Email services like Mailgun, Mailchimp etc in the field. In this piece of article, I am going to discuss how you can send 10,000 Email/Month free of cost from Django using Mailgun API

Now remember, here we are using our own company or personal email address for sending the mail to customer.

You can access the entire tutorial code here.

https://github.com/narenaryan/mailtest

Step 1 : Registering the account

First visit https://mailgun.com to register your free account.

Now you need only two important things to send email from your mailgun account. Those are:

  • API BASE URL.
  • API_KEY

Step 2 : Registering the domain

Now add your domain to mailgun and get your API BASE URL, API_KEY
You must verify the domain before using it. To verify you need to add three DNS records in your domain provider. Two TXT and one CNAME records. All the details are clearly documented in Mailgun. To recieve mail you need to additionally configure MX records. Now we are looking only about sending email from Django.

Step 3 : Python API usage

Now coming to the point, irrespective of what framework we are using we can send emails from Python code using mailgun API. See this simple snippet that sends email from my personal email.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import requests

def send_simple_message(API_BASE_URL, API_KEY):
    return requests.post(
        API_BASE_URL,
        auth=("api", API_KEY),
        data={"from": "Developer contact@narenarya.in",
              "to": ["customer1@gmail.com", "customer2@gmail.com"],
              "subject": "Hello!",
              "text": "Thanks for signing up with us!."})

send_simple_message("https://api.mailgun.net/v3/narenarya.in/messages",
                    "key-5891601XXXXXXXXXXXXXXXf")

You see that API is just a POST request with API key authorization, you need to know about what fields you are going to pass. You can also have in line images in Mailgun emails. The mail will be sent from contact@narenarya.in in the abvoe case.

Step 4 : Django and Celery from scratch

You can access the entire tutorial code here.

https://github.com/narenaryan/mailtest

Django has a good celery support which lets us to send Email as a worker task instead of blocking code request. Since it is a non-urgent request, we can add it as a celery task instead of executing as a normal python request.

Let us begin everything from scratch so that it will be a definitvie guide.

$ virtualenv mailgunenv
$ source mailgunenv/bin/activate
$ pip install django celery requests django-celery ipython

Note: I always stress to have requests and IPython

Here I am using dj-celery to store results in Django ORM backend. Now create a new project called mailtest and sample app .

$ django-admin startproject mailtest
$ cd mailtest
$ python manage.py startapp sample

Now my folder tree looks like this. I am using Python3 here.

First create a file called celery.py in mailtest folder where settings.py lies.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# mailtest/celery.py
from __future__ import absolute_import

import os

from celery import Celery

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mailtest.settings')

from django.conf import settings  # noqa

app = Celery('mailtest')

# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))

Now open the __init__.py file in project folder and add following lines.

1
2
3
4
from __future__ import absolute_import
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app  # noqa

So now set MAILGUN_BASE_URL, MAILGUN_API_KEY in your django settings.py and add sample app and django-celery to installed apps.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sample',
    'djcelery'
]

...

# Since we are using Database ORM as our celery backend. 
# Redis or Rabbit MQ used for this purpose other way.

app.conf.update(
CELERY_RESULT_BACKEND='djcelery.backends.database:DatabaseBackend',
)

MAILGUN_BASE_URL = "https://api.mailgun.net/v3/narenarya.in/messages"
MAILGUN_API_KEY = "key-5891601XXXXXXXXXXXXXXXf"

Now we need to migrate our models for sample and django-celery.

$ python manage.py migrate

step 5 : Add a celery task and run celery to process them

We have finished setting up celery with our Django nicely. Now we need to actually make a celery task which sends Email. For that add tasks.py to sample app.

# sample/tasks.py
from __future__ import absolute_import
import requests
from celery import shared_task

# Define mailgun sending email API as a celery task
@shared_task(name="tsask.send_email")
def send_email(API_BASE_URL, API_KEY, CUSTOMER_LIST):
    return requests.post(
        API_BASE_URL,
        auth=("api", API_KEY),
        data={"from": "Developer contact@narenarya.in",
              "to": CUSTOMER_LIST,
              "subject": "Hello!",
              "text": "Thanks for signing up with us!."})

Cool. Now we have everything to go on and test. Now lauch a new terminal window and run celery process from Project root (i.e where manage.py lies)

$ celery -A mailtest worker -l info

It starts celery workers to listen for the tasks submitted. Now fire up another terminal and launch python (or Ipython) shell.

$ python manage.py shell

Enter the following to submit a task.

> from django.conf import settings as st
> from sample.tasks import send_email
> customer_list = ["narenarya@live.com", "narenarya246@yahoo.com"]
> send_email.delay(st.MAILGUN_BASE_URL, st.MAILGUN_API_KEY, customer_list)

This actually creates a celery task and submits it to the celery worker. If tasks are more than workers, then tasks sits on the backend queue. Now if you see the first terminal saying task is recieved and processing it. When task successfully processed you would see an email sent to customer list email addresses.

So you can add this line of code in whatever view you of Django to send an email.

1
2
# Submitting a task to celery in Django code
send_email.delay(MAILGUN_BASE_URL, MAILGUN_API_KEY, customer_list)

You can see status of mail in celery terminal

And at the same time I got a message from Developer(contact@narenarya.in) to my gmail address.

In this way you can use 10,000 emails freely every month for your startup which runs on Django.

You can access the entire tutorial code here.

https://github.com/narenaryan/mailtest

References

Thank you :). Drop a comment if you have any query at narenarya@live.com


Comments

comments powered by Disqus