2
votes

I am trying to send confirmation email to my registered user using Django and Celery. I am using RabbitMQ as the Broker. Whenever I'm executing the code, the celery log shows it is receiving the task and executing successfully, But I am not receiving any emails.

tasks.py

from celery.task import Task
from django.core.mail import send_mail
from django.template import loader
from django.utils.html import strip_tags
from config.celery import app
from config.settings import default


class SendConfirmationEmail(Task):

    def __init__(self, *args, **kwargs):
        self.user_name = kwargs.get('username')
        self.user_id = kwargs.get('id')
        self.user_hash = kwargs.get('hash')
        self.user_email = kwargs.get('email')

    def send_email(self):
        confirm_mail = loader.render_to_string('mail/confirmation.html',
                                           {'user': self.user_name, 'id': self.user_id,
                                            'hash': self.user_hash,
                                            'domain': default.SITE_URL})
        text_email = strip_tags(confirm_mail)
        send_mail(
            subject='Confirm Your E-mail',
            message=text_email,
            from_email='[email protected]',
            recipient_list=[self.user_email],
            fail_silently=False,
            html_message=confirm_mail
        )

     def run(self, *args, **kwargs):
         self.send_email()

app.register_task(SendConfirmationEmail())

signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from apps.siteuser.models import User
from apps.siteuser.tasks import SendConfirmationEmail


@receiver(post_save, sender=User)
def create_employee_details(sender, instance, created, **kwargs):
    if created:
        task = SendConfirmationEmail(username=instance.first_name, id=instance.id, hash=instance.hash,
                                 email=instance.email)
        task.delay()

settings for Email & Celery:

CELERY_BROKER_URL = 'amqp://username:password@localhost:5672/vhost'

EMAIL_HOST = 'smtp.mailtrap.io'
EMAIL_HOST_USER = MY_USERNAME
EMAIL_HOST_PASSWORD = MY_PASSWORD
EMAIL_PORT = 2525

Celery log:

[2018-05-09 11:50:41,191: INFO/MainProcess] Received task: apps.user.tasks.SendConfirmationEmail[e63c0f5f-7b81-4065-85c1-9ef87acc792a]
[2018-05-09 11:50:41,197: INFO/ForkPoolWorker-1] Task apps.user.tasks.SendConfirmationEmail[e63c0f5f-7b81-4065-85c1-9ef87acc792a] succeeded in 0.004487647999667388s: None

NOTE: I have sent mail without Celery and it was working fine. But The Problem started after trying with Celery.I am using Mailtrap for development purpose.

1
task = SendConfirmationEmail () ?? where is SendConfirmationEmail. send_email() ?? or SendConfirmationEmail.run() - Vaibhav
On the next line I'm running task.delay() which I think execute run method on the class. - SK. Fazlee Rabby
I would do it with shared_task from celery import shared_task - Lemayzeur
why do u use a class-based approach? is not simpler to convert it to just @task() def send_email(username, id, hash, email): ...? and then run send_email.delay(username, id, hash, email) from your signal? 2) if this is a delayed task - why u have written a special signal for it? it does not affect on the performance, you can write it from view, before .save() method. Or you can send email in signal without delaying it. These are 2 alternatives, which u use one in one. - Chiefir
@Chiefir Actually the signal will perform some other task upon saving the instance. this was just a part of the code. I liked to use the Class Based approach but it did not work. using @shared_task decorator solved the problem. Thanks - SK. Fazlee Rabby

1 Answers

3
votes

This is how I generally call a celery task

Task.py

from celery import shared_task


@shared_task
def task1(*args,**kwargs):
    pass

Caller.py

from task import task1


task1.delay(a,b,c...)

Is celery discovery configured correctly?