feat(email): 添加发件人邮箱字段并优化邮件发送逻辑
添加独立的sender_email字段作为发件人邮箱,优先使用该字段而非smtp_username 更新相关表单、模型和测试用例以支持新字段 重构邮件发送逻辑,统一邮箱格式验证和错误提示
This commit is contained in:
@@ -52,6 +52,7 @@ def test_celery_email_config():
|
||||
'smtp_server': config.smtp_server,
|
||||
'smtp_port': config.smtp_port,
|
||||
'smtp_username': config.smtp_username,
|
||||
'sender_email': config.sender_email,
|
||||
'recipient_email': config.recipient_email,
|
||||
}
|
||||
|
||||
@@ -81,9 +82,10 @@ def test_celery_email_config():
|
||||
import re
|
||||
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
||||
|
||||
# 验证发件人邮箱格式
|
||||
if config.smtp_username and not re.match(email_pattern, config.smtp_username):
|
||||
logger.error(f"发件人邮箱格式不正确: {config.smtp_username}")
|
||||
# 验证发件人邮箱格式(优先使用sender_email,其次使用smtp_username)
|
||||
sender_email = config.sender_email or config.smtp_username
|
||||
if sender_email and not re.match(email_pattern, sender_email):
|
||||
logger.error(f"发件人邮箱格式不正确: {sender_email}")
|
||||
logger.error("请在系统配置页面输入有效的邮箱地址")
|
||||
return False
|
||||
|
||||
@@ -200,9 +202,10 @@ def celery_send_test_email(self, test_mode=True):
|
||||
from core.models import SystemConfig
|
||||
from django.core.mail.backends.smtp import EmailBackend
|
||||
config = SystemConfig.get_config()
|
||||
from_email = config.smtp_username
|
||||
# 优先使用sender_email,其次使用smtp_username作为发件人
|
||||
from_email = config.sender_email or config.smtp_username
|
||||
if not from_email:
|
||||
raise ValueError("未配置发件邮箱 (smtp_username)")
|
||||
raise ValueError("未配置发件邮箱")
|
||||
|
||||
# 验证发件人邮箱格式
|
||||
import re
|
||||
@@ -265,7 +268,7 @@ def celery_send_test_email(self, test_mode=True):
|
||||
任务ID: {task_id}
|
||||
|
||||
这是一封测试邮件,用于验证Celery异步邮件发送功能。
|
||||
""
|
||||
"""
|
||||
|
||||
# 创建邮件
|
||||
email = EmailMessage(
|
||||
@@ -342,7 +345,8 @@ def celery_send_html_report_email(self, include_attachment=False):
|
||||
from core.models import SystemConfig
|
||||
from django.core.mail.backends.smtp import EmailBackend
|
||||
config = SystemConfig.get_config()
|
||||
from_email = config.smtp_username
|
||||
# 优先使用sender_email,其次使用smtp_username作为发件人
|
||||
from_email = config.sender_email or config.smtp_username
|
||||
if not from_email:
|
||||
raise ValueError("未配置发件邮箱")
|
||||
|
||||
@@ -380,29 +384,29 @@ def celery_send_html_report_email(self, include_attachment=False):
|
||||
'insights': {'count': 0, 'items': []},
|
||||
}
|
||||
|
||||
# 创建HTML邮件内容
|
||||
html_content = f"""
|
||||
# 创建HTML邮件内容(使用普通字符串拼接,避免f-string中的%语法问题)
|
||||
html_content = '''
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
body {{ font-family: 'Microsoft YaHei', Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; }}
|
||||
.header {{ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px 20px; text-align: center; }}
|
||||
.header h1 {{ margin: 0; font-size: 24px; }}
|
||||
.header .date {{ font-size: 14px; opacity: 0.9; margin-top: 10px; }}
|
||||
.content {{ padding: 20px; background: #f9f9f9; }}
|
||||
.section {{ background: white; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
|
||||
.section h2 {{ color: #667eea; font-size: 18px; margin-top: 0; border-bottom: 2px solid #667eea; padding-bottom: 10px; }}
|
||||
.stat {{ display: inline-block; background: #667eea; color: white; padding: 5px 15px; border-radius: 20px; margin: 5px; }}
|
||||
.footer {{ text-align: center; padding: 20px; color: #666; font-size: 12px; }}
|
||||
.success-badge {{ background: #28a745; color: white; padding: 10px 20px; border-radius: 5px; display: inline-block; }}
|
||||
body { font-family: 'Microsoft YaHei', Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; }
|
||||
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px 20px; text-align: center; }
|
||||
.header h1 { margin: 0; font-size: 24px; }
|
||||
.header .date { font-size: 14px; opacity: 0.9; margin-top: 10px; }
|
||||
.content { padding: 20px; background: #f9f9f9; }
|
||||
.section { background: white; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
||||
.section h2 { color: #667eea; font-size: 18px; margin-top: 0; border-bottom: 2px solid #667eea; padding-bottom: 10px; }
|
||||
.stat { display: inline-block; background: #667eea; color: white; padding: 5px 15px; border-radius: 20px; margin: 5px; }
|
||||
.footer { text-align: center; padding: 20px; color: #666; font-size: 12px; }
|
||||
.success-badge { background: #28a745; color: white; padding: 10px 20px; border-radius: 5px; display: inline-block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>📊 家庭日报</h1>
|
||||
<div class="date">{report_data['today']}</div>
|
||||
<div class="date">{today}</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
@@ -410,15 +414,15 @@ def celery_send_html_report_email(self, include_attachment=False):
|
||||
<h2>✅ 邮件发送测试</h2>
|
||||
<p>这是一封通过 <strong>Celery异步任务</strong> 发送的HTML格式邮件。</p>
|
||||
<p><strong>任务ID:</strong> {task_id}</p>
|
||||
<p><strong>发送时间:</strong> {timezone.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
|
||||
<p><strong>发送时间:</strong> {send_time}</p>
|
||||
<p><strong>状态:</strong> <span class="success-badge">发送成功</span></p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>📈 统计信息</h2>
|
||||
<p>阅读记录: <span class="stat">{report_data['reading']['count']} 篇</span></p>
|
||||
<p>感悟记录: <span class="stat">{report_data['insights']['count']} 条</span></p>
|
||||
<p>家庭事项: <span class="stat">{len(report_data['tasks'])} 项</span></p>
|
||||
<p>阅读记录: <span class="stat">{reading_count} 篇</span></p>
|
||||
<p>感悟记录: <span class="stat">{insights_count} 条</span></p>
|
||||
<p>家庭事项: <span class="stat">{tasks_count} 项</span></p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
@@ -435,7 +439,14 @@ def celery_send_html_report_email(self, include_attachment=False):
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
'''.format(
|
||||
today=report_data['today'],
|
||||
task_id=task_id,
|
||||
send_time=timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
reading_count=report_data['reading']['count'],
|
||||
insights_count=report_data['insights']['count'],
|
||||
tasks_count=len(report_data['tasks'])
|
||||
)
|
||||
|
||||
# 创建邮件后端
|
||||
backend = EmailBackend(
|
||||
@@ -462,13 +473,16 @@ def celery_send_html_report_email(self, include_attachment=False):
|
||||
|
||||
# 添加附件(如果需要)
|
||||
if include_attachment:
|
||||
attachment_content = f"""家庭日报测试报告
|
||||
发送时间: {timezone.now().isoformat()}
|
||||
attachment_content = '''家庭日报测试报告
|
||||
发送时间: {send_time}
|
||||
任务ID: {task_id}
|
||||
发送方式: Celery异步任务
|
||||
|
||||
这是一份自动生成的测试报告。
|
||||
"""
|
||||
这是一份自动生成的测试报告
|
||||
'''.format(
|
||||
send_time=timezone.now().isoformat(),
|
||||
task_id=task_id
|
||||
)
|
||||
email.attach('daily_report_test.txt', attachment_content, 'text/plain')
|
||||
logger.info(f"[任务 {task_id}] 已添加测试附件")
|
||||
|
||||
@@ -604,7 +618,8 @@ def main():
|
||||
|
||||
# 从数据库获取邮件配置
|
||||
config = SystemConfig.get_config()
|
||||
from_email = config.smtp_username
|
||||
# 优先使用sender_email,其次使用smtp_username作为发件人
|
||||
from_email = config.sender_email or config.smtp_username
|
||||
if not from_email:
|
||||
raise ValueError("未配置发件邮箱")
|
||||
|
||||
@@ -628,19 +643,21 @@ def main():
|
||||
fail_silently=False
|
||||
)
|
||||
|
||||
subject = f"[直接测试] Celery邮件测试 - {timezone.now().strftime('%H:%M:%S')}"
|
||||
body = f"""
|
||||
这是直接发送的测试邮件,用于验证SMTP配置。
|
||||
subject = "[直接测试] Celery邮件测试 - {}".format(timezone.now().strftime('%H:%M:%S'))
|
||||
body = '''
|
||||
这是直接发送的测试邮件,用于验证SMTP配置
|
||||
|
||||
发送时间: {timezone.now().isoformat()}
|
||||
发送时间: {send_time}
|
||||
发送方式: 直接发送(非Celery)
|
||||
|
||||
如果Celery异步任务测试失败,但此测试成功,
|
||||
说明SMTP配置正确,问题可能在Celery或Redis配置。
|
||||
如果Celery异步任务测试失败,但此测试成功
|
||||
说明SMTP配置正确,问题可能在Celery或Redis配置
|
||||
|
||||
---
|
||||
家庭日报系统
|
||||
"""
|
||||
'''.format(
|
||||
send_time=timezone.now().isoformat()
|
||||
)
|
||||
|
||||
email = EmailMessage(
|
||||
subject=subject,
|
||||
|
||||
Reference in New Issue
Block a user