Milano
Milano

Reputation: 18735

Asynchronious email sending in Django

I'm trying to figure out how to send email asynchroniously so User don't have to wait until email is sent.

I've installer celery and django-celery-email and added django-celery-email into my settings.py - djcelery_email.

I've also changed database backend:

EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend'

Now I've tried to do an action which sends email but it freezes and no email has been sent.

Do you know what to do?

Here is a traceback from cmd:

Internal Server Error: /ajax/reservation/confirm/
Traceback (most recent call last):
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\django\core\handlers\base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\django\core\handlers\base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\django\views\decorators\csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\dolava_app\views.py", line 68, in reservation_confirm
    reservation.save()
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\dolava_app\models.py", line 150, in save
    notifications.AdminNotifications.new_pair(self, paired_reservation)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\dolava_app\notifications.py", line 79, in new_pair
    send_message_to_admin(subject,message)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\dolava_app\notifications.py", line 8, in send_message_to_admin
    mail.send()
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\django\core\mail\message.py", line 292, in send
    return self.get_connection(fail_silently).send_messages([self])
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\djcelery_email\backends.py", line 17, in send_messages
    result_tasks.append(send_emails.delay(chunk, self.init_kwargs))
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\celery\app\task.py", line 453, in delay
    return self.apply_async(args, kwargs)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\celery\app\task.py", line 565, in apply_async
    **dict(self._get_exec_options(), **options)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\celery\app\base.py", line 354, in send_task
    reply_to=reply_to or self.oid, **options
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\celery\app\amqp.py", line 310, in publish_task
    **kwargs
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\kombu\messaging.py", line 172, in publish
    routing_key, mandatory, immediate, exchange, declare)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\kombu\connection.py", line 457, in _ensured
    interval_max)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\kombu\connection.py", line 369, in ensure_connection
    interval_start, interval_step, interval_max, callback)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\kombu\utils\__init__.py", line 246, in retry_over_time
    return fun(*args, **kwargs)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\kombu\connection.py", line 237, in connect
    return self.connection
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\kombu\connection.py", line 742, in connection
    self._connection = self._establish_connection()
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\kombu\connection.py", line 697, in _establish_connection
    conn = self.transport.establish_connection()
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\kombu\transport\pyamqp.py", line 116, in establish_connection
    conn = self.Connection(**opts)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\amqp\connection.py", line 165, in __init__
    self.transport = self.Transport(host, connect_timeout, ssl)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\amqp\connection.py", line 186, in Transport
    return create_transport(host, connect_timeout, ssl)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\amqp\transport.py", line 299, in create_transport
    return TCPTransport(host, connect_timeout)
  File "C:\Users\Milano\PycharmProjects\FutileStudio\dolava\venv\lib\site-packages\amqp\transport.py", line 95, in __init__
    raise socket.error(last_err)
error: [Errno 10061] No connection could be made because the target machine actively refused it

Upvotes: 0

Views: 1105

Answers (1)

lukeaus
lukeaus

Reputation: 12255

Problem

From https://github.com/pmclanahan/django-celery-email

By default django-celery-email will use Django's builtin SMTP email backend for the actual sending of the mail.

This means you need to run an SMTP server locally to accept the email. That is why you are getting a socket error - cause you don't have any SMTP server set to receive the email.


Possible Solutions - Local Development

A. Start an SMTP server and use your own client

Option 1

Run a combined SMTP server and client. Mailcatcher is great for this.

It even comes with django setup instructions!

Set it up then fire it up with:

$ mailcatcher -fv

Note: mailcatcher requires gem (ruby package manager) to install. So you will have to install that first. Its probably worth the effort, as mailcatcher works quite nicely and gives you html and text representations of the email in a browser tab.

For docker users you can get a mailcatcher docker image


Option 2

Run your own SMTP server and a separate mail client.

e.g. Use a simple python SMTP server From the command line python -m smtpd -n -c DebuggingServer localhost:1025

in your django settings:

EMAIL_HOST = 'localhost' EMAIL_HOST_USER = None EMAIL_HOST_PASSWORD = None EMAIL_PORT = 1025 EMAIL_USE_TLS = False

Then you will need to setup a client to get those emails.


B. Don't use SMTP as a backend in your settings

Instead print to the console:

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

Problem with this is ugly formatting. HTML will appear as text which makes the email very hard to read. You can output this to a file by manually copying and pasting it into a .html file and opening it in a browser, but that will get boring very fast.


Solution - Continuous Integration Server

Use this for making email accessible to the django test client, so you can check that emails got sent, check the content of email programatically etc. EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'

Solution - Production Server

You will need to use a SMTP server again. Either you can run your own or use Sendgrid, Mailgun, Mandrill or something similar.

Upvotes: 1

Related Questions