You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Celery和Django发送带图片附件的邮件?解决序列化报错

解决Celery发送带图片邮件的JSON序列化错误问题

问题根源

直接将photo.file(文件对象/字节流)作为Celery任务参数传递时,Celery默认的JSON序列化器无法处理字节类型或文件对象,从而触发Object of type bytes is not JSON serializable错误。

解决方案:用Base64编码传递图片内容

把图片内容编码为可被JSON序列化的Base64字符串,在任务中再解码回字节流,具体修改如下:

1. 修改views.py

导入base64模块,读取图片字节并转成Base64字符串:

import base64
from main_app.tasks import send_creator_submission_email_task


class BecomeCreatorView(TemplateView):
    template_name = 'become_creator.html'
    become_creator_form = BecomeCreatorForm
    success_url = reverse_lazy('index')

    def get(self, request, *args, **kwargs):
        form = self.become_creator_form()
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.become_creator_form(request.POST, request.FILES)
        if form.is_valid():
            photo = form.cleaned_data['photo']
            # 读取图片字节并转为Base64字符串
            image_bytes = photo.read()
            image_base64 = base64.b64encode(image_bytes).decode('utf-8')
            # 传递slug、Base64字符串、文件名
            send_creator_submission_email_task.delay(self.kwargs.get('slug'), image_base64, photo.name)
            messages.success(request, "Thank you!")
            return redirect(self.success_url)
        messages.error(request, "Error!")
        return render(request, self.template_name, {'form': form})

2. 修改tasks.py

任务接收Base64字符串后直接传递给邮件函数即可:

@shared_task
def send_creator_submission_email_task(slug, image_base64, image_filename):
    return send_creator_submission_email(slug, image_base64, image_filename)

3. 修改email.py

导入base64模块,将Base64字符串解码回字节流用于附件,同时替换reverse_lazy为reverse(同步环境下无需懒加载):

import base64
from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.core.mail import EmailMultiAlternatives
from django.conf import settings
from django.contrib.sites.models import Site
from django.urls import reverse


def send_creator_submission_email(slug, image_base64, image_filename):
    user = get_object_or_404(User, slug=slug)
    current_site = Site.objects.get_current().domain

    email_context = {
        'current_site': current_site,
        'user_email': user.email,
        'user_slug': user.slug,
        'approve_url': f"http://{current_site}{reverse('approve_user', kwargs={'slug': user.slug})}",
        "decline_url": f"http://{current_site}{reverse('decline_user', kwargs={'slug': user.slug})}"
    }

    html_message = render_to_string('email/admin_decision_email.html', email_context)
    plain_message = strip_tags(html_message)

    email = EmailMultiAlternatives(
        subject="New creator submission",
        body=plain_message,
        from_email=settings.DEFAULT_FROM_EMAIL,
        to=[settings.EMAIL_ADMIN],
    )

    email.attach_alternative(html_message, "text/html")
    # 解码Base64字符串为字节流并添加附件
    image_bytes = base64.b64decode(image_base64)
    email.attach(image_filename, image_bytes)
    email.send()

额外提示

  • Base64编码会让数据体积增加约30%,如果图片过大,建议先将图片存储到服务器或云存储,再把文件路径传递给Celery任务,而非直接传递图片内容。
  • 同步执行场景下,reverse_lazy的懒加载特性没有意义,替换为reverse可以避免潜在的加载异常。

内容的提问来源于stack exchange,提问作者jmur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 07:22:43