test
This commit is contained in:
54
app/utils.py
54
app/utils.py
@@ -2,6 +2,7 @@ import smtplib
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import sys
|
||||||
from email.parser import BytesParser
|
from email.parser import BytesParser
|
||||||
from email.policy import default
|
from email.policy import default
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -11,37 +12,57 @@ import asyncore
|
|||||||
import base64
|
import base64
|
||||||
from .config import Config
|
from .config import Config
|
||||||
|
|
||||||
# 配置日志
|
# 配置日志输出到控制台
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.DEBUG, # 改为 DEBUG 级别
|
||||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
handlers=[
|
||||||
|
logging.StreamHandler(sys.stdout)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
logger = logging.getLogger('smtp_server')
|
logger = logging.getLogger('smtp_server')
|
||||||
|
|
||||||
# 初始化 Redis 客户端
|
# 初始化 Redis 客户端
|
||||||
redis_client = redis.from_url(Config.REDIS_URL)
|
redis_client = redis.from_url(Config.REDIS_URL)
|
||||||
|
|
||||||
|
|
||||||
class CustomSMTPServer(smtpd.SMTPServer):
|
class CustomSMTPServer(smtpd.SMTPServer):
|
||||||
|
def __init__(self, localaddr, remoteaddr):
|
||||||
|
logger.info(f"Initializing SMTP server on {localaddr}")
|
||||||
|
super().__init__(localaddr, remoteaddr)
|
||||||
|
|
||||||
def process_message(self, peer, mailfrom, rcpttos, data):
|
def process_message(self, peer, mailfrom, rcpttos, data):
|
||||||
try:
|
try:
|
||||||
|
logger.debug(f"Connection from peer: {peer}")
|
||||||
|
logger.debug(f"Mail from: {mailfrom}")
|
||||||
|
logger.debug(f"Recipients: {rcpttos}")
|
||||||
|
logger.debug(f"Raw data length: {len(data)} bytes")
|
||||||
|
|
||||||
# 记录接收到的邮件基本信息
|
# 记录接收到的邮件基本信息
|
||||||
logger.info(f"Received mail from {mailfrom} to {rcpttos}")
|
logger.info(f"Received mail from {mailfrom} to {rcpttos}")
|
||||||
|
|
||||||
# 验证收件人域名
|
# 验证收件人域名
|
||||||
|
valid_recipients = []
|
||||||
for rcpt in rcpttos:
|
for rcpt in rcpttos:
|
||||||
if not rcpt.endswith('@nosqli.com'):
|
if not rcpt.endswith('@nosqli.com'):
|
||||||
logger.warning(f"Rejected mail to {rcpt}: invalid domain")
|
logger.warning(f"Rejected mail to {rcpt}: invalid domain")
|
||||||
continue
|
else:
|
||||||
|
valid_recipients.append(rcpt)
|
||||||
|
|
||||||
|
if not valid_recipients:
|
||||||
|
logger.error("No valid recipients found")
|
||||||
|
return
|
||||||
|
|
||||||
# 解析邮件
|
# 解析邮件
|
||||||
|
logger.debug("Parsing email data...")
|
||||||
email = BytesParser(policy=default).parsebytes(data)
|
email = BytesParser(policy=default).parsebytes(data)
|
||||||
|
|
||||||
# 获取邮件正文
|
# 获取邮件正文
|
||||||
body = self._get_email_body(email)
|
body = self._get_email_body(email)
|
||||||
|
logger.debug(f"Email body length: {len(body) if body else 0}")
|
||||||
|
|
||||||
# 处理附件
|
# 处理附件
|
||||||
attachments = self._process_attachments(email)
|
attachments = self._process_attachments(email)
|
||||||
|
logger.debug(f"Found {len(attachments)} attachments")
|
||||||
|
|
||||||
# 构建邮件数据
|
# 构建邮件数据
|
||||||
timestamp = datetime.now().isoformat()
|
timestamp = datetime.now().isoformat()
|
||||||
@@ -51,7 +72,7 @@ class CustomSMTPServer(smtpd.SMTPServer):
|
|||||||
'message_id': message_id,
|
'message_id': message_id,
|
||||||
'subject': email.get('subject', ''),
|
'subject': email.get('subject', ''),
|
||||||
'sender': mailfrom,
|
'sender': mailfrom,
|
||||||
'recipients': json.dumps(rcpttos),
|
'recipients': json.dumps(valid_recipients),
|
||||||
'body': body,
|
'body': body,
|
||||||
'timestamp': timestamp,
|
'timestamp': timestamp,
|
||||||
'attachments': json.dumps(attachments),
|
'attachments': json.dumps(attachments),
|
||||||
@@ -71,12 +92,18 @@ class CustomSMTPServer(smtpd.SMTPServer):
|
|||||||
def _get_email_body(self, email):
|
def _get_email_body(self, email):
|
||||||
"""提取邮件正文"""
|
"""提取邮件正文"""
|
||||||
try:
|
try:
|
||||||
|
logger.debug("Extracting email body...")
|
||||||
if email.is_multipart():
|
if email.is_multipart():
|
||||||
for part in email.walk():
|
for part in email.walk():
|
||||||
if part.get_content_type() == "text/plain":
|
if part.get_content_type() == "text/plain":
|
||||||
return part.get_payload(decode=True).decode()
|
content = part.get_payload(decode=True).decode()
|
||||||
|
logger.debug(f"Found text/plain content: {len(content)} chars")
|
||||||
|
return content
|
||||||
else:
|
else:
|
||||||
return email.get_payload(decode=True).decode()
|
content = email.get_payload(decode=True).decode()
|
||||||
|
logger.debug(f"Found single part content: {len(content)} chars")
|
||||||
|
return content
|
||||||
|
logger.warning("No text content found in email")
|
||||||
return ""
|
return ""
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error extracting email body: {str(e)}")
|
logger.error(f"Error extracting email body: {str(e)}")
|
||||||
@@ -86,6 +113,7 @@ class CustomSMTPServer(smtpd.SMTPServer):
|
|||||||
"""处理邮件附件"""
|
"""处理邮件附件"""
|
||||||
attachments = []
|
attachments = []
|
||||||
try:
|
try:
|
||||||
|
logger.debug("Processing attachments...")
|
||||||
if email.is_multipart():
|
if email.is_multipart():
|
||||||
for part in email.walk():
|
for part in email.walk():
|
||||||
if part.get_content_maintype() == 'multipart':
|
if part.get_content_maintype() == 'multipart':
|
||||||
@@ -95,6 +123,7 @@ class CustomSMTPServer(smtpd.SMTPServer):
|
|||||||
|
|
||||||
filename = part.get_filename()
|
filename = part.get_filename()
|
||||||
if filename:
|
if filename:
|
||||||
|
logger.debug(f"Processing attachment: {filename}")
|
||||||
attachment_data = part.get_payload(decode=True)
|
attachment_data = part.get_payload(decode=True)
|
||||||
attachments.append({
|
attachments.append({
|
||||||
'filename': filename,
|
'filename': filename,
|
||||||
@@ -102,6 +131,7 @@ class CustomSMTPServer(smtpd.SMTPServer):
|
|||||||
'content_type': part.get_content_type(),
|
'content_type': part.get_content_type(),
|
||||||
'size': len(attachment_data)
|
'size': len(attachment_data)
|
||||||
})
|
})
|
||||||
|
logger.debug(f"Attachment processed: {filename} ({len(attachment_data)} bytes)")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error processing attachments: {str(e)}")
|
logger.error(f"Error processing attachments: {str(e)}")
|
||||||
return attachments
|
return attachments
|
||||||
@@ -109,22 +139,27 @@ class CustomSMTPServer(smtpd.SMTPServer):
|
|||||||
def _store_email(self, email_data):
|
def _store_email(self, email_data):
|
||||||
"""存储邮件到 Redis"""
|
"""存储邮件到 Redis"""
|
||||||
try:
|
try:
|
||||||
|
logger.debug("Storing email in Redis...")
|
||||||
# 使用 message_id 作为主键
|
# 使用 message_id 作为主键
|
||||||
email_key = f"email:{email_data['message_id']}"
|
email_key = f"email:{email_data['message_id']}"
|
||||||
redis_client.hmset(email_key, email_data)
|
redis_client.hmset(email_key, email_data)
|
||||||
|
logger.debug(f"Stored email with key: {email_key}")
|
||||||
|
|
||||||
# 为每个收件人创建索引
|
# 为每个收件人创建索引
|
||||||
recipients = json.loads(email_data['recipients'])
|
recipients = json.loads(email_data['recipients'])
|
||||||
for recipient in recipients:
|
for recipient in recipients:
|
||||||
recipient_key = f"recipient:{recipient}"
|
recipient_key = f"recipient:{recipient}"
|
||||||
redis_client.lpush(recipient_key, email_key)
|
redis_client.lpush(recipient_key, email_key)
|
||||||
|
logger.debug(f"Created recipient index: {recipient_key}")
|
||||||
|
|
||||||
# 创建时间索引
|
# 创建时间索引
|
||||||
time_key = f"time:{email_data['timestamp']}"
|
time_key = f"time:{email_data['timestamp']}"
|
||||||
redis_client.set(time_key, email_key)
|
redis_client.set(time_key, email_key)
|
||||||
|
logger.debug(f"Created time index: {time_key}")
|
||||||
|
|
||||||
# 设置过期时间(可选,这里设置为30天)
|
# 设置过期时间(可选,这里设置为30天)
|
||||||
redis_client.expire(email_key, 30 * 24 * 60 * 60)
|
redis_client.expire(email_key, 30 * 24 * 60 * 60)
|
||||||
|
logger.debug("Set expiration time: 30 days")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error storing email: {str(e)}")
|
logger.error(f"Error storing email: {str(e)}")
|
||||||
@@ -136,6 +171,7 @@ def start_smtp_server(host='0.0.0.0', port=25):
|
|||||||
try:
|
try:
|
||||||
logger.info(f"Starting SMTP server on {host}:{port}")
|
logger.info(f"Starting SMTP server on {host}:{port}")
|
||||||
server = CustomSMTPServer((host, port), None)
|
server = CustomSMTPServer((host, port), None)
|
||||||
|
logger.info("SMTP server initialized, entering main loop...")
|
||||||
asyncore.loop()
|
asyncore.loop()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error starting SMTP server: {str(e)}")
|
logger.error(f"Error starting SMTP server: {str(e)}")
|
||||||
|
|||||||
Reference in New Issue
Block a user