最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Django发送邮件

    正文概述    2020-08-06   276


    Django发送邮件

    当我们创建一个网站时,经常会有发送邮件的需要。无论是用户注册,还是用户忘记密码,又或者是用户下单后进行付款确认,都需要发

    送不同的邮件。所以发送邮件的需求实际上是非常重要的,而且如果如果不在一开始就建造结构清晰的邮件服务,到后面可能会是一团糟。

    基本的邮件发送

    假设我们希望在用户注册到我们的网站。我们可以参照Django文档,向验证通过并创建成功的用户发送邮件。具体实现如下:

    import logging
    
    from rest_framework.views import APIView
    from django.http import JsonResponse
    from django.core.mail import send_mail
    
    from users.models import User
    
    logger = logging.getLogger('django')
    
    
    class RegisterView(APIView):
    
        def post(self, request):
            # Run validations
            if not request.data:
                return JsonResponse({'errors': 'User data must be provided'}, status=400)
            if User.objects.filter(email=request.data['email']).exists():
                return JsonResponse({'errors': 'Email already in use'}, status=400)
            try:
                # Create new user
                user = User.objects.create_user(email=request.data['email'].lower())
                user.set_password(request.data['password'])
                user.save()
                
                # Send welcome email
                send_mail(
                    subject='Welcome!',
                    message='Hey there! Welcome to our platform.',
                    html_message='<p><strong>Het there!</strong> Welcome to our platform.</p>'
                    from_email='from@example.com',
                    recipient_list=[user.email],
                    fail_silently=False,
                )
                
                return JsonResponse({'status': 'ok'})
            except Exception as e:
                logger.error('Error at %s', 'register view', exc_info=e)
                return JsonResponse({'errors': 'Wrong data provided'}, status=400)

    当然肯定文档中所说的那样,你也必须提前设定好一些重要的配置项,例如EMAIL_HOST和EMAIL_PORT。

    很好!现在我们已经发送了欢迎邮件!

    创建一个mailer类

    正如我之前所说,在我们的应用中不同的模块可能都需要发送邮件,所以最好有一个电子邮件服务或者mailer类来处理所有的邮件请求。更简单,因为我们不再需要每次都去翻遍全部代码。

    iimport logging
    
    from django.conf import settings
    from django.core.mail import send_mail
    
    from users.models import User
    
    logger = logging.getLogger('django')
    
    
    class BaseMailer():
        def __init__(self, to_email, subject, message, html_message):
            self.to_email = to_email
            self.subject = subject
            self.message = message
            self.html_message = html_message
    
        def send_email(self):
            send_mail(
                subject=self.subject,
                message=self.message,
                html_message=self.html_message,
                from_email='from@example.com',
                recipient_list=[self.to_email],
                fail_silently=False,
            )

    让我们来看看经过这次改变后,注册服务的视图层是某种子:

    import logging
    
    from rest_framework.views import APIView
    from django.http import JsonResponse
    from django.core.mail import send_mail
    
    from users.models import User
    from users.mailers import BasicMailer
    
    logger = logging.getLogger('django')
    
    
    class RegisterView(APIView):
    
        def post(self, request):
            # Run validations
            if not request.data:
                return JsonResponse({'errors': 'User data must be provided'}, status=400)
            if User.objects.filter(email=request.data['email']).exists():
                return JsonResponse({'errors': 'Email already in use'}, status=400)
            try:
                # Create new user
                user = User.objects.create_user(email=request.data['email'].lower())
                user.set_password(request.data['password'])
                user.save()
                
                # Send welcome email
                BasicMailer(to_email=user.email, 
                            subject='Welcome!', 
                            message='Hey there! Welcome to our platform.', 
                            html_message='<p><strong>Het there!</strong> Welcome to our platform.</p>').send_email()
                
                return JsonResponse({'status': 'ok'})
            except Exception as e:
                logger.error('Error at %s', 'register view', exc_info=e)
                return JsonResponse({'errors': 'Wrong data provided'}, status=400)
    
    作者:cyril_lee
    链接:https://juejin.im/post/5eb6171c5188256d7a3cac97
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    mailer子类

    现在我们已经把所有的“邮件代码”移动到一个单独的地方,可以把它利用起来啦!这时候可以继续创建特定的mailer类,并让它们知道每次被调用时该发送什么内容。让我们创建一个mailer类用来在每次用户注册时进行调用,另一个mailer类用来发送订单的确认信息。

    import logging
    
    from django.conf import settings
    from django.core.mail import send_mail
    
    from users.models import User
    
    logger = logging.getLogger('django')
    
    
    class BaseMailer():
        def __init__(self, to_email, subject, message, html_message):
            self.to_email = to_email
            self.subject = subject
            self.message = message
            self.html_message = html_message
    
        def send_email(self):
            send_mail(
                subject=self.subject,
                message=self.message,
                html_message=self.html_message,
                from_email='from@example.com',
                recipient_list=[self.to_email],
                fail_silently=False,
            )
            
            
    class RegisterMailer(BaseMailer):
        def __init__(self, to_email):
            super().__init__(to_email,  
                             subject='Welcome!', 
                             message='Hey there! Welcome to our platform.', 
                             html_message='<p><strong>Het there!</strong> Welcome to our platform.</p>')
            
    
    class NewOrderMailer(BaseMailer):
        def __init__(self, to_email):
            super().__init__(to_email,  
                             subject='New Order', 
                             message='You have just created a new order', 
                             html_message='<p>You have just created a new order.</p>')

    这表明在不同的场景下集成邮件服务是非常简单的。你只需要构造一个基础的邮件类来进行实现,然后在子类中设置具体内容。

    因为不用实现所有邮件相关的代码,所以现在我们注册服务的视图层看起来更加简明:

    import logging
    
    from rest_framework.views import APIView
    from django.http import JsonResponse
    from django.core.mail import send_mail
    
    from users.models import User
    from users.mailers import RegisterMailer
    
    logger = logging.getLogger('django')
    
    
    class RegisterView(APIView):
    
        def post(self, request):
            # Run validations
            if not request.data:
                return JsonResponse({'errors': 'User data must be provided'}, status=400)
            if User.objects.filter(email=request.data['email']).exists():
                return JsonResponse({'errors': 'Email already in use'}, status=400)
            try:
                # Create new user
                user = User.objects.create_user(email=request.data['email'].lower())
                user.set_password(request.data['password'])
                user.save()
                
                # Send welcome email
                RegisterMailer(to_email=user.email).send_email()
                
                return JsonResponse({'status': 'ok'})
            except Exception as e:
                logger.error('Error at %s', 'register view', exc_info=e)
                return JsonResponse({'errors': 'Wrong data provided'}, status=400)

    使用Sendgrid

    假设我们必须使用正式的蟒库将我们的邮件服务后端迁移Sendgrid(一个用于交易和营销邮件的客户通信平台)。我们将不能再使用的Django的SEND_EMAIL方法,而且我们还不得不使用新库的语法。

    嗯,但我们还是很幸运的地方!因为我们已经将所有与邮件管理相关的代码都放到了一个单独的地方,所以我们可以很轻松的进行这场比赛

    import logging
    
    from django.conf import settings
    from sendgrid import SendGridAPIClient, Email, Personalization
    from sendgrid.helpers.mail import Mail
    
    from users.models import User
    
    logger = logging.getLogger('django')
    
    
    class BaseMailer():
        def __init__(self, email, subject, template_id):
            self.mail = Mail()
            self.subject = subject
            self.template_id = template_id
    
        def create_email(self):
            self.mail.from_email = Email(settings.FROM_EMAIL)
            self.mail.subject = self.subject
            self.mail.template_id = self.template_id
            personalization = Personalization()
            personalization.add_to(Email(self.user.email))
            self.mail.add_personalization(personalization)
    
        def send_email(self):
            self.create_email()
            try:
                sg = SendGridAPIClient(settings.SENDGRID_API_KEY)
                sg.send(self.mail)
            except Exception as e:
                logger.error('Error at %s', 'mailer', exc_info=e)
                
    
    class RegisterMailer(BaseMailer):
        def __init__(self, to_email):
            super().__init__(to_email, subject='Welcome!', template_id=1234)
    
            
    class NewOrderMailer(BaseMailer):
        def __init__(self, to_email):
            super().__init__(to_email, subject='New Order', template_id=5678)

    请注意,您必须在配置文件中设置Sendgrid的api密钥,以及指定需要被使用的模板的ID,Sendrid会直接从自己的页面中根据这个ID来加载指定的html邮件模版。

    太好了!这并不困难,而且我们不用去修改发送邮件的每一行代码。

    现在让我们的步子再迈大一点。

    根据域信息定制邮件内容

    当然我们发送邮件的时候,有时候可能也会使用一些域信息来填充模板。比如说,如果在欢迎邮件里面能有新用户的名字,那肯定会显得更友好。Sendgrid 允许你在邮件模板中定义变量,这些变量将替换为从我们这里接收的实际信息。所以现在让我们来添加这部分数据吧!

    import logging
    
    from django.conf import settings
    from sendgrid import SendGridAPIClient, Email, Personalization
    from sendgrid.helpers.mail import Mail
    
    from users.models import User
    
    logger = logging.getLogger('django')
    
    
    class BaseMailer():
        def __init__(self, email, subject, template_id):
            self.mail = Mail()
            self.user = User.objects.get(email=email)
            self.subject = subject
            self.template_id = template_id
            self.substitutions = {
                'user_name': self.user.first_name,
                'user_surname': self.user.last_name
            }
    
    
        def create_email(self):
            self.mail.from_email = Email(settings.FROM_EMAIL)
            self.mail.subject = self.subject
            self.mail.template_id = self.template_id
            personalization = Personalization()
            personalization.add_to(Email(self.user.email))
            personalization.dynamic_template_data = self.substitutions
            self.mail.add_personalization(personalization)
    
        def send_email(self):
            self.create_email()
            try:
                sg = SendGridAPIClient(settings.SENDGRID_API_KEY)
                sg.send(self.mail)
            except Exception as e:
                logger.error('Error at %s', 'mailer', exc_info=e)
                
    
    class RegisterMailer(BaseMailer):
        def __init__(self, to_email):
            super().__init__(to_email, subject='Welcome!', template_id=1234)
    
            
    class NewOrderMailer(BaseMailer):
        def __init__(self, to_email):
            super().__init__(to_email, subject='New Order', template_id=5678)

    这里我看到的唯一一个问题是替换方案不那么灵活。很可能会发生的情况是,我们传递的数据可能是用户根据请求的上下文访问不到的。比如说,新的订单编号、重置密码的链接等等。这些变量参数可能很多,把它们作为命名参数传递可能会让代码变得比较脏乱。我们希望的是一个基于关键字,并且长度可变的参数列表,一般来说会被定义为 **kwargs,但在此我们命名它为 **substitutions,让这个表达会更形象:

    import loggingfrom django.conf import settingsfrom sendgrid import SendGridAPIClient, Email, Personalizationfrom sendgrid.helpers.mail import Mailfrom users.models import User
    
    logger = logging.getLogger('django')class BaseMailer():
        def __init__(self, email, subject, template_id, **substitutions):
            self.mail = Mail()
            self.user = User.objects.get(email=email)
            self.subject = subject
            self.template_id = template_id
            self.substitutions = {            'user_name': self.user.first_name,            'user_surname': self.user.last_name
            }        
            for key in substitutions:
                self.substitutions.update({key: substitutions[key]})    def create_email(self):
            self.mail.from_email = Email(settings.FROM_EMAIL)
            self.mail.subject = self.subject
            self.mail.template_id = self.template_id
            personalization = Personalization()
            personalization.add_to(Email(self.user.email))
            personalization.dynamic_template_data = self.substitutions
            self.mail.add_personalization(personalization)    def send_email(self):
            self.create_email()        try:
                sg = SendGridAPIClient(settings.SENDGRID_API_KEY)
                sg.send(self.mail)        except Exception as e:
                logger.error('Error at %s', 'mailer', exc_info=e)            class RegisterMailer(BaseMailer):
        def __init__(self, to_email, **substitutions):
            super().__init__(to_email, subject='Welcome!', template_id=1234, **substitutions)        class NewOrderMailer(BaseMailer):
        def __init__(self, to_email):
            super().__init__(to_email, subject='New Order', template_id=5678, **substitutions)

    如果希望将额外信息传递给 mailer 类,就需要按如下编码:

    NewOrderMailer(user.email, order_id=instance.id).send_email()
    PasswordResetMailer(user.email, key=password_token.key).send_email()

    总结

    我们已经创建了一个灵活的 mailer 类,它将所有与电子邮件相关的代码封装在一个单独的地方,使代码维护变得更容易,并且还接收可变的上下文参数来填充电子邮件内容!一下子设计这整个方案肯定会很困难,但是我们一步一步的去实现就会简单得多,并且会在这个过程中受益良多。我鼓励你基于这个设计,继续开发邮件附件的功能!

    更多python相关文章请关注python自学网。


    起源地下载网 » Django发送邮件

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元