Python烧瓶多进程:无法“呈现”用于发送网格电子邮件正文的html页面

Posted

技术标签:

【中文标题】Python烧瓶多进程:无法“呈现”用于发送网格电子邮件正文的html页面【英文标题】:Python flask multiprocess: cannot "render" a html page for the send grid email body 【发布时间】:2022-01-13 17:09:35 【问题描述】:

为了带来一些背景,我有一个很大的特定功能,它作为一个多进程在后台运行。也就是第二个过程(以后可能会更多)。

这样做的原因是它会重定向到一个表明请求成功的 html 页面。 毕竟,在他的数据请求通过并转换数据之前,客户不会在加载页面上等待超过 7 分钟。是的,这是我的应用程序所做的必不可少的。在你问为什么这需要这么长时间之前,这与 JSON 数据的结构有关。

简而言之,AKA 第一次请求获取数据点列表,然后对每个数据点分别进行第二次请求,因为详细信息的请求 url 在该数据点内。

在此后台进程的最后一步,邮件将通过发送网格发送,根据文件是否太大,它会发送一个带有特殊“本地文件”链接的附件以供下载。邮件的文本会根据情况有不同的内容,但您必须从中获得的主要内容是,无论文件是否作为附件,您将始终拥有本地文件“下载位置”。

import os
import base64
from datetime import datetime
from flask import Flask
import  Classified.background_script.converter.GIPOD_Converter as data_conv
from flask import send_file, send_from_directory, safe_join, abort, render_template, jsonify
from Classified import app
from celery import Celery
import random
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import (
    Mail, Attachment, FileContent, FileName,
    FileType, Disposition, ContentId)
from sendgrid import SendGridAPIClient
import Classified.background_script.sendgrid as mail_delivery


send_grid_mail = 'Classified'
sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))

app = Flask(__name__)


def main(file_name: str,file_location:str, attachment_bool: bool, download_link:str, recipient_email: str):
    file_path = file_location
    if os.getenv('SENDGRID_API_KEY') == None:
        print("No API KEY FOUND")
    else:
        print("API KEY FOUND")
    html_string = generate_html_content(attachment_bool,download_link)
    message = Mail(
            from_email='Classified',
            to_emails=recipient_email,
            subject='Uw data is gereed.',
            html_content= html_string)

    if attachment_bool is True:
        with open(file_path, 'rb') as f:
            data = f.read()
            f.close()
        encoded_file = base64.b64encode(data).decode()
        attachment = Attachment()
        attachment.file_content = FileContent(encoded_file)
        attachment.file_type = FileType('application/zip')
        attachment.file_name = FileName('.zip'.format(file_name))
        attachment.disposition = Disposition('attachment')
        attachment.content_id = ContentId('Example Content ID')
        message.attachment = attachment
    try:     
            response = sg.send(message)
            print(response.status_code)
            print(response.body)
            print(response.headers)
    except Exception as e:
            print("Failed scenario")
            print("Scenerio checking")


# Generates the HTML variables for the email page.
def generate_html_content(attachment_bool: bool, download_link: str):
    if attachment_bool is False:
        Letter_1 = "Helaas was deze te groot om via mail door te sturen."
        Letter_2 = "Klik hier om het bestand te downloaden."
    if attachment_bool is True:
        Letter_1 =  "U vindt het bestand terug in de bijlage."
        Letter_2 = "Is het bestand niet in de bijlage terug te vinden? Klik dan hier en download dan hier."
    return render_template(
        'email.html',
        message_1 = Letter_1,
        message_2 = Letter_2,
        link = download_link,
        title='YOU GOT MAIL'
         )










if __name__ == "__main__":
    main()

您可能会问我为什么要使用 html 页面渲染功能?好吧,因为以下原因

本质上,我是在渲染一个带有变量的静态模板

但是当它不是多进程时,我遇到了一个我没有遇到过的特定问题。

Traceback (most recent call last):
  File "D:\IDE\Anaconda3\envs\PYTHONGDAL\lib\multiprocessing\process.py", line 315, in _bootstrap
    self.run()
  File "D:\IDE\Anaconda3\envs\PYTHONGDAL\lib\multiprocessing\process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "D:\Programmeer portfolio\FLASK\Classfiied\Classfiied\views.py", line 178, in execute_order66
    Order66.main(stringpart,url,sper_year,email)
  File "D:\Programmeer portfolio\FLASK\Classfiied\Classfiied\background_script\backgroundtask.py", line 53, in main
    mail_delivery.main(file_name,requested_data,attachment_bool,requested_data,email)
  File "D:\Programmeer portfolio\FLASK\Classfiied\Classfiied\background_script\sendgrid\send_mail.py", line 30, in main
    html_string = generate_html_content(attachment_bool,download_link)
  File "D:\Programmeer portfolio\FLASK\Classfiied\Classfiied\background_script\sendgrid\send_mail.py", line 67, in generate_html_content
    return render_template(
  File "D:\IDE\Anaconda3\envs\Classfiied\lib\site-packages\flask\templating.py", line 146, in render_template
    ctx.app.update_template_context(context)
AttributeError: 'NoneType' object has no attribute 'app'

我不明白为什么会出现此错误,是我需要做一些特别的事情,还是我必须走不同的路线,并编写完整的 HTML?

【问题讨论】:

一些拼写错误。 A.K.A 是 known as 的缩写。虽然我的英语说得非常好(我的母语是荷兰语),但我通常会犯很多我忽略的拼写错误。我只是阅读了它们,即使在双重/三重检查时也是如此。 【参考方案1】:

这里是 Twilio SendGrid 开发人员宣传员。

跟踪结束时的错误是:

  File "D:\IDE\Anaconda3\envs\Classfiied\lib\site-packages\flask\templating.py", line 146, in render_template
    ctx.app.update_template_context(context)
AttributeError: 'NoneType' object has no attribute 'app'

这告诉我ctx 对象在这里是NoneType,它不应该是。我认为问题在于您在烧瓶应用程序的上下文之外运行此代码,它没有运行 Flask 路由来响应传入的 HTTP 请求,您只是将其作为常规函数调用。当它不是多进程时,我猜这是在 Flask 路由的上下文中运行的。

我查看了如何在 Flask 路由之外使用render_template,最终遇到了these examples on Full Stack Python,特别是示例4,它使用render_template 呈现HTML,然后作为电子邮件发送。 example is from flask-base 并使用 with app.app_context() 在 Flask 应用程序的上下文中运行代码,而不是路由的一部分。

我通常不是 Python 程序员,但也许这样的东西适用于您的应用程序:

def generate_html_content(attachment_bool: bool, download_link: str):
    if attachment_bool is False:
        Letter_1 = "Helaas was deze te groot om via mail door te sturen."
        Letter_2 = "Klik hier om het bestand te downloaden."
    if attachment_bool is True:
        Letter_1 =  "U vindt het bestand terug in de bijlage."
        Letter_2 = "Is het bestand niet in de bijlage terug te vinden? Klik dan hier en download dan hier."
    with app.app_context():
      return render_template(
          'email.html',
          message_1 = Letter_1,
          message_2 = Letter_2,
          link = download_link,
          title='YOU GOT MAIL'
      )

让我知道这是否有帮助。

【讨论】:

感谢您提供此信息,这实际上是问题所在,实际上我在您回答之前自己发现了它,我不得不将所有 HTML 单独编写到一个非 Flask 相关函数中,然后它就起作用了.我会把你的答案标记为正确的,谢谢。

以上是关于Python烧瓶多进程:无法“呈现”用于发送网格电子邮件正文的html页面的主要内容,如果未能解决你的问题,请参考以下文章

Python 多处理管理器在烧瓶 API 中使用时显示错误

无法使用烧瓶邮件python将附件添加到邮件

在烧瓶模板中呈现 html 字符串

无法使用 CID 将文件添加为内联附件 python 烧瓶

烧瓶(uwsgi)应用程序上的守护进程后台任务

使用烧瓶+蓝图发送邮件