email_sender.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import smtplib
  2. from email.mime.multipart import MIMEMultipart
  3. from email.mime.text import MIMEText
  4. from email.mime.base import MIMEBase
  5. from email import encoders
  6. import os
  7. from jinja2 import Template
  8. from pathlib import Path
  9. from Config.EmailConfig import EMAIL_CONFIG, EMAIL_TEMPLATE_CONFIG, SMTP_CONFIG
  10. from Utils.Log import log_for_api
  11. import requests
  12. import json
  13. logger = log_for_api()
  14. class EmailSender:
  15. """邮件发送器 - 使用SMTP协议与OAuth 2.0认证"""
  16. def __init__(self):
  17. self.config = EMAIL_CONFIG
  18. self.template_config = EMAIL_TEMPLATE_CONFIG
  19. self.smtp_config = SMTP_CONFIG
  20. self.access_token = None
  21. def get_oauth2_token(self):
  22. """获取OAuth 2.0访问令牌"""
  23. try:
  24. # 这里需要替换为你的Azure应用注册信息
  25. client_id = self.smtp_config.get("client_id", "")
  26. client_secret = self.smtp_config.get("client_secret", "")
  27. tenant_id = self.smtp_config.get("tenant_id", "")
  28. scope = "https://outlook.office365.com/.default"
  29. token_url = f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token"
  30. data = {
  31. 'client_id': client_id,
  32. 'scope': scope,
  33. 'client_secret': client_secret,
  34. 'grant_type': 'client_credentials'
  35. }
  36. response = requests.post(token_url, data=data)
  37. response.raise_for_status()
  38. token_data = response.json()
  39. self.access_token = token_data['access_token']
  40. return True
  41. except Exception as e:
  42. logger.error(f"获取OAuth 2.0令牌时出错: {e}")
  43. return False
  44. def render_email_template(self, test_results, report_info):
  45. """渲染邮件HTML模板"""
  46. # 保持不变...
  47. def send_email(self, test_results, report_info, attachment_path=None):
  48. """通过SMTP发送邮件(使用OAuth 2.0认证)"""
  49. try:
  50. # 获取OAuth 2.0访问令牌
  51. if not self.get_oauth2_token():
  52. logger.error("无法获取OAuth 2.0访问令牌")
  53. return False
  54. # 创建邮件消息
  55. msg = MIMEMultipart()
  56. msg['From'] = self.smtp_config["sender_email"]
  57. msg['To'] = ', '.join(self.config["recipients"])
  58. msg['Subject'] = self.config["subject"]
  59. # 如果有抄送和密送
  60. if self.config["cc_recipients"]:
  61. msg['Cc'] = ', '.join(self.config["cc_recipients"])
  62. # 渲染HTML内容
  63. html_body = self.render_email_template(test_results, report_info)
  64. msg.attach(MIMEText(html_body, 'html'))
  65. # 添加附件
  66. if attachment_path and os.path.exists(attachment_path):
  67. part = MIMEBase('application', 'octet-stream')
  68. with open(attachment_path, 'rb') as file:
  69. part.set_payload(file.read())
  70. encoders.encode_base64(part)
  71. part.add_header(
  72. 'Content-Disposition',
  73. f'attachment; filename={os.path.basename(attachment_path)}'
  74. )
  75. msg.attach(part)
  76. logger.info(f"已添加附件: {attachment_path}")
  77. # 连接SMTP服务器并发送邮件
  78. with smtplib.SMTP(self.smtp_config["smtp_server"], self.smtp_config["smtp_port"]) as server:
  79. server.ehlo()
  80. server.starttls()
  81. server.ehlo()
  82. # 使用OAuth 2.0认证
  83. auth_string = f"user={self.smtp_config['sender_email']}\x01auth=Bearer {self.access_token}\x01\x01"
  84. auth_string = auth_string.encode()
  85. server.docmd("AUTH", "XOAUTH2 " + auth_string.decode())
  86. # 发送邮件
  87. all_recipients = (
  88. self.config["recipients"] +
  89. self.config["cc_recipients"] +
  90. self.config["bcc_recipients"]
  91. )
  92. server.sendmail(
  93. self.smtp_config["sender_email"],
  94. all_recipients,
  95. msg.as_string()
  96. )
  97. logger.info("邮件已成功发送!")
  98. return True
  99. except Exception as e:
  100. logger.error(f"发送邮件时出错: {e}")
  101. return False