如何使用 Celery 在 Django 中发送异步邮件?
How to Send Asynchronous Emails In Django Using Celery?
我正在尝试使用 django-celery-email 和 Celery 3.1.17 在 Django 1.6.2 应用程序中发送异步电子邮件,并使用 RabbitMQ 3.5.0 作为我的消息代理和结果后端。正在发送和接收电子邮件,但在发送电子邮件时,我的 Celery 日志中也出现错误 "django.core.mail... is not JSON serializable"。我正在使用 JSON 在 Celery 中进行序列化,因为 pickle 已被弃用。有什么方法可以更改我的配置以防止发生此错误?顺带一提,当我不使用Celery的延迟方法时,我可以发送电子邮件。
谢谢。
# Stacktrace
Task app.tasks.send_email with id 7ac1eb8e-c090-4893-8147-1f204e463d12 raised exception:
'EncodeError(TypeError("<module \'django.core.mail\' from \'/Users/me/venv/django/lib/python2.7/site-packages/django/core/mail/__init__.pyc\'> is not JSON serializable",),)'
Task was called with args: [] kwargs: {}.
The contents of the full traceback was:
Traceback (most recent call last):
File "/Users/me/venv/django/lib/python2.7/site-packages/celery/app/trace.py", line 283, in trace_task
uuid, retval, SUCCESS, request=task_request,
File "/Users/me/venv/django/lib/python2.7/site-packages/celery/backends/amqp.py", line 136, in store_result
delivery_mode=self.delivery_mode,
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/messaging.py", line 161, in publish
compression, headers)
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/messaging.py", line 237, in _prepare
body) = dumps(body, serializer=serializer)
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 164, in dumps
payload = encoder(data)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/contextlib.py", line 35, in __exit__
self.gen.throw(type, value, traceback)
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 59, in _reraise_errors
reraise(wrapper, wrapper(exc), sys.exc_info()[2])
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 55, in _reraise_errors
yield
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 164, in dumps
payload = encoder(data)
File "/Users/me/venv/django/lib/python2.7/site-packages/anyjson/__init__.py", line 141, in dumps
return implementation.dumps(value)
File "/Users/me/venv/django/lib/python2.7/site-packages/anyjson/__init__.py", line 87, in dumps
return self._encode(data)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 243, in dumps
return _default_encoder.encode(obj)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 270, in iterencode
return _iterencode(o, 0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default
raise TypeError(repr(o) + " is not JSON serializable")
EncodeError: <module 'django.core.mail' from '/Users/me/venv/django/lib/python2.7/site-packages/django/core/mail/__init__.pyc'> is not JSON serializable
# settings.py
# MAIL SETTINGS
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = 'me'
EMAIL_HOST_PASSWORD ='password'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
FAIL_SILENTLY = False
# CELERY SETTINGS
BROKER_URL = 'amqp://guest@localhost//'
CELERY_RESULT_BACKEND = 'amqp'
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json', ]
# DJANGO-CELERY-EMAIL
INSTALLED_APPS += ('djcelery_email', )
EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend'
# tasks.py
from __future__ import absolute_import
import smtplib
from conf.celery import app
from django.core import mail
from django.template.loader import render_to_string
@app.task
def send_email():
to_email = 'me@example.com'
subject = 'Testing Celery/RabbitMQ'
from_email = 'me2@example.com'
message = 'This is a test of my Celery/RabbitMQ function.'
recipient_list = []
recipient_list.append(to_email)
html_message = render_to_string('send_mail.html', {'message': message})
try:
mail.send_mail(subject, message, from_email, recipient_list, html_message)
except smtplib.SMTPException, e:
return 0
return mail
# views.py
from app.tasks import send_email
def home_page(request, template):
# Send mail synchronously
#send_email()
# Send email asynchronously.
send_email.delay()
return render(request, template)
您收到了预期的错误。 Celery 设置为使用 JSON 序列化,并使用内置的 json
库尝试序列化 django.core.mail
,这显然不支持任何形式的序列化。
它在没有 delay
的情况下调用时工作的原因是因为它的工作方式就像调用一个典型的函数(在同一进程中)。
如果您必须 return 任务中的某些内容,您可以 return 支持序列化的值或对象的字典。对于自定义序列化,您可以使用 serializer
属性 并在调用任务时传递您的自定义 decoder/encoder。
在你的情况下,你可以 return 类似 {'success': True}
的东西和任何失败的 False 值。
More options 关于使用自定义序列化程序
我正在尝试使用 django-celery-email 和 Celery 3.1.17 在 Django 1.6.2 应用程序中发送异步电子邮件,并使用 RabbitMQ 3.5.0 作为我的消息代理和结果后端。正在发送和接收电子邮件,但在发送电子邮件时,我的 Celery 日志中也出现错误 "django.core.mail... is not JSON serializable"。我正在使用 JSON 在 Celery 中进行序列化,因为 pickle 已被弃用。有什么方法可以更改我的配置以防止发生此错误?顺带一提,当我不使用Celery的延迟方法时,我可以发送电子邮件。
谢谢。
# Stacktrace
Task app.tasks.send_email with id 7ac1eb8e-c090-4893-8147-1f204e463d12 raised exception:
'EncodeError(TypeError("<module \'django.core.mail\' from \'/Users/me/venv/django/lib/python2.7/site-packages/django/core/mail/__init__.pyc\'> is not JSON serializable",),)'
Task was called with args: [] kwargs: {}.
The contents of the full traceback was:
Traceback (most recent call last):
File "/Users/me/venv/django/lib/python2.7/site-packages/celery/app/trace.py", line 283, in trace_task
uuid, retval, SUCCESS, request=task_request,
File "/Users/me/venv/django/lib/python2.7/site-packages/celery/backends/amqp.py", line 136, in store_result
delivery_mode=self.delivery_mode,
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/messaging.py", line 161, in publish
compression, headers)
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/messaging.py", line 237, in _prepare
body) = dumps(body, serializer=serializer)
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 164, in dumps
payload = encoder(data)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/contextlib.py", line 35, in __exit__
self.gen.throw(type, value, traceback)
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 59, in _reraise_errors
reraise(wrapper, wrapper(exc), sys.exc_info()[2])
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 55, in _reraise_errors
yield
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 164, in dumps
payload = encoder(data)
File "/Users/me/venv/django/lib/python2.7/site-packages/anyjson/__init__.py", line 141, in dumps
return implementation.dumps(value)
File "/Users/me/venv/django/lib/python2.7/site-packages/anyjson/__init__.py", line 87, in dumps
return self._encode(data)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 243, in dumps
return _default_encoder.encode(obj)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 270, in iterencode
return _iterencode(o, 0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default
raise TypeError(repr(o) + " is not JSON serializable")
EncodeError: <module 'django.core.mail' from '/Users/me/venv/django/lib/python2.7/site-packages/django/core/mail/__init__.pyc'> is not JSON serializable
# settings.py
# MAIL SETTINGS
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = 'me'
EMAIL_HOST_PASSWORD ='password'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
FAIL_SILENTLY = False
# CELERY SETTINGS
BROKER_URL = 'amqp://guest@localhost//'
CELERY_RESULT_BACKEND = 'amqp'
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json', ]
# DJANGO-CELERY-EMAIL
INSTALLED_APPS += ('djcelery_email', )
EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend'
# tasks.py
from __future__ import absolute_import
import smtplib
from conf.celery import app
from django.core import mail
from django.template.loader import render_to_string
@app.task
def send_email():
to_email = 'me@example.com'
subject = 'Testing Celery/RabbitMQ'
from_email = 'me2@example.com'
message = 'This is a test of my Celery/RabbitMQ function.'
recipient_list = []
recipient_list.append(to_email)
html_message = render_to_string('send_mail.html', {'message': message})
try:
mail.send_mail(subject, message, from_email, recipient_list, html_message)
except smtplib.SMTPException, e:
return 0
return mail
# views.py
from app.tasks import send_email
def home_page(request, template):
# Send mail synchronously
#send_email()
# Send email asynchronously.
send_email.delay()
return render(request, template)
您收到了预期的错误。 Celery 设置为使用 JSON 序列化,并使用内置的 json
库尝试序列化 django.core.mail
,这显然不支持任何形式的序列化。
它在没有 delay
的情况下调用时工作的原因是因为它的工作方式就像调用一个典型的函数(在同一进程中)。
如果您必须 return 任务中的某些内容,您可以 return 支持序列化的值或对象的字典。对于自定义序列化,您可以使用 serializer
属性 并在调用任务时传递您的自定义 decoder/encoder。
在你的情况下,你可以 return 类似 {'success': True}
的东西和任何失败的 False 值。
More options 关于使用自定义序列化程序