Anuj TBE
Anuj TBE

Reputation: 9790

django mail queue emails not sending with celery

I'm using Django Mail Queue with Django 2.x

The application is hosted on Heroku and using redis backend for Celery

The settings.py file contains

##################
# CELERY STUFF
##################
BROKER_URL = os.getenv('REDIS_URL', 'redis://localhost:6379')
CELERY_RESULT_BACKEND = os.getenv('REDIS_URL', 'redis://localhost:6379')
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

#######################
# Django mail queue
#######################
MAILQUEUE_CELERY = True
MAILQUEUE_QUEUE_UP = False

and sending email like

new_message = MailerMessage()
new_message.subject = subject
new_message.to_address = to
new_message.from_address = from_email
new_message.content = text_content
new_message.html_content = html_content
new_message.app = 'Koober'
new_message.save()

On sending the email, it is saved in the database and is shown on the Admin page but is not sent.

Setting MAILQUEUE_CELERY = False and MAILQUEUE_QUEUE_UP = False is sending email successfully.

But this is resulting in application failure in case of an exception. That's why I want to use Celery to send email in the background.

enter image description here

app/celery.py

from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'koober.settings')
app = Celery('koober')

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))

Upvotes: 0

Views: 1866

Answers (1)

Burhan Khalid
Burhan Khalid

Reputation: 174624

From the documentation:

A cron job can be set up to work one of two ways: using a management command or an HTTP request. Both methods run the mail queue which grabs emails and sends them. To decrease load, it only tries to send 30 emails at a time. This number can be changed by using MAILQUEUE_LIMIT in settings

The idea is that the messages are queued up for sending, and you have to manually trigger the workers to send messages. The preferred method is to do this by running the send_queued_messages management command:

python manage.py send_queued_messages

From your comment:

As per this line in the documentation Instead of using the cron job the celery task worker will attempt to send email when it’s saved. The cron job will clean up any emails that get lost. I do not need to run the management command when MAILQUEUE_CELERY = True.

By default, the application doesn't need celery to work. It works synchronously (at the same time) - which is how the default mail functionality of django works.

As soon as the application reaches the code to send mail, it will attempt to send mail and pause until it gets a response, then continue with the rest of the request.

The other option is to defer sending of the email and instead of using the same process as the web, use a secondary process (the worker) at the same time. This is what happens when you set MAILQUEUE_CELERY = True.

If you set MAILQUEUE_QUEUE_UP = True as you have done, now messages are accepted but queued, and you must use the management command or cron to send messages.

So, if you want messages to be sent immediately, set MAILQUEUE_QUEUE_UP to False.

If you want to send messages in batches in intervals, set MAILQUEUE_QUEUE_UP to True, and then setup a cron job to run the management command.

Upvotes: 1

Related Questions