如何从Azure函数应用程序发送电子邮件?

7

我运行了一个使用Python语言的Azure函数App,因为业务需求需要从函数应用程序发送电子邮件。

为此,我编写了一个Python函数。

from email.message import EmailMessage
import smtplib

def send_mail():
    # message to be sent
    msg = EmailMessage()
    msg.set_content('Test content')

    msg['Subject'] = 'Test'
    msg['From'] = "test@hotmail.com"
    msg['To'] = ["test@hotmail.com"]

    # creates SMTP session 
    s = smtplib.SMTP('smtp-mail.outlook.com', 587) 
    s.ehlo()

    # start TLS for security 
    s.starttls() 
    # Authentication 
    s.login("test@hotmail.com", "password-to-login") 
      
    # sending the mail 
    s.send_message(msg)
    
    # terminating the session 
    s.quit() 

    return

上述代码在本地机器上运行正常。如果我将相同的代码移动到 Azure Function 应用程序中,它就无法工作。

我该如何使其在 Azure Function 应用程序中正常工作?

我该如何在 Azure Function 应用程序中使用 Gmail 发送电子邮件?

4个回答

21

由于公共云服务IP的弹性以及可能被滥用的潜在风险,从Azure计算服务托管的电子邮件服务器直接向外部域(如outlook.com、gmail.com等)发送出站电子邮件不受支持。因此,Azure计算IP地址块已添加到公共块列表(如Spamhaus PBL)。该政策没有例外。

由于我们不支持从我们的平台运行SMTP服务器,这不应影响我们。

目前在Azure Web应用程序中使用邮件功能的唯一方法是通过SMTP中继。第三方服务(如SendGrid)提供此类服务。

在Azure Web应用程序架构中,实际的Web应用程序位于共同的前端之后,这些前端由托管在该数据中心上的所有站点共享。

该数据中心中托管的站点之一可能正在发送垃圾电子邮件,这可能导致IP地址被邮件服务器列入黑名单。因此,从该地址发送的电子邮件将被拒绝或被邮件服务器视为垃圾邮件。   VM或Cloud Services的情况下也存在此限制。Azure使用一组IP地址,并且这些地址是可重复使用的。这意味着您可能会获得已被列入黑名单的IP地址,因为有人之前从该地址发送垃圾邮件,因此您的电子邮件将被邮件服务器拒绝或视为垃圾邮件。

这是云计算中常见的情况,通常建议使用像 SendGrid 这样的外部邮件服务提供商来进行消息传递。   SendGrid 相关文章:

如何在 Azure 中使用 SendGrid 发送电子邮件:https://azure.microsoft.com/zh-cn/documentation/articles/sendgrid-dotnet-how-to-send-email/


如果我在Azure Functions与应用服务计划中拥有专用IP地址,使用SMTP服务器发送电子邮件是否是一个好的解决方案?因为SendGrid不是免费的,而且是第三方工具。 - Pingpong
这可能是StackOverflow上最好的答案 - 无与伦比。谢谢。 - JozeV
FYI:您也可以使用逻辑应用SMTP模块而不是“函数应用程序”。 - djangofan
那么为什么微软有一个图形邮件客户端呢?我从这里和其他相关文档 https://learn.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=http https://damienbod.com/2021/08/09/send-emails-using-microsoft-graph-api-and-a-desktop-client/ 的理解是,您可以发送邮件,并且 Azure 门户将为您提供 SMTP 服务器。从我所检查的情况来看,甚至不需要在 Azure 中配置 SMTP 服务器。 - Alex

3
我建议您使用一些第三方电子邮件服务,例如SendGrid/Twillio。您可以将SendGrid输出绑定到Python Azure函数中。在function.json中,绑定应该看起来像这里
这里有一个例子

有没有办法在不使用第三方解决方案(如sendGrid)的情况下发送电子邮件? - Anbarasu Subramaniyan
你为什么要把事情搞得那么难?SendGrid 免费提供25000封电子邮件。https://stackoverflow.com/questions/50059171/not-able-to-connect-to-smtp-from-azure-cloud-service - Sajeetharan

1

我即将实施一种黑客方法。在我的情况下,我不太关心主题、附件等。这是一封信息邮件。

  • 在您的代码中添加一个日志消息,以可解析的形式记录电子邮件正文。
  • 创建一个基于日志的警报规则,匹配该日志。

当Azure Monitor看到此日志时,它将向配置在警报中的电子邮件地址发送警报。电子邮件可以包括日志消息的内容。

如上所述,这非常受限:

  • 无法完全控制主题行
  • 不能轻松地以编程方式控制收件人
  • 无法附加文件

它是否自动包含日志消息的内容,还是需要做一些操作来包含它? - dll
1
@dll 这是一个警报的配置。如果设置,警报邮件将包含日志消息。 - Kashyap
是的,谢谢,非常好用,正是我需要的,而且很容易操作。 - dll
这也是我如何使用Application Insights触发警报/通知的方式。您可以向Application Insights发送自定义日志消息,并通过Application Insights中的自定义查询配置警报/通知。 - hui chen

1

以下是手动使用Python在Azure Functions中使SendGrid工作的实际步骤。 这不是最优解,因为Azure有自己的内部解决方案,可能更优,但这是一种快速简单的方法。

在本地计算机上运行pip install sendgrid

在您的代码中包含:

from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail

发送电子邮件:(请记住这不是安全的,因为 API 密钥已经暴露,但这是一个快速启动的方式。)

    message = Mail(
        from_email='yourfromemail@gmail.com',
        to_emails='toemail@gmail.com',
        subject='Email Subject Line Here',
        html_content='<strong>HTML CONTENT HERE</strong>')
    try:
        sg = SendGridAPIClient('YOUR API KEY HERE')
        response = sg.send(message)
        print(response.status_code)
        print(response.body)
        print(response.headers)
    except Exception as e:
        raise Exception(str(e) + ' -> Error Reported')

最后一步是,如果您想在实际的Azure函数服务器上运行此功能,则需要将其添加到requirements.txt中。

sendgrid

请注意,sendgrid免费发送电子邮件的数量为25,000封,因此它非常适合大多数情况。您只需要在其网站上设置API密钥,按照他们的说明操作即可。对我来说很简单,只需花费约5分钟创建一个“用户”和与之关联的API密钥。
还要注意,当我使用sendgrid时,我能够从我的GMAIL帐户发送电子邮件。然而,请注意,由于谷歌无法真正验证是您发送了Gmail,因此它将经常进入您的垃圾邮件文件夹,请记住这个缺陷。对于我来说,由于我只是进行测试工作,这并不重要,但对于生产工作可能会有问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接