#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
本地SMTP中继服务器 - 将邮件转发到外部邮箱
支持两种方式:
1. 直接投递(会被拒收): python smtp_relay_server.py --direct
2. 通过QQ邮箱中继(推荐): python smtp_relay_server.py --relay
"""

import asyncio
import smtplib
import sys
from datetime import datetime
from aiosmtpd.controller import Controller
from aiosmtpd.handlers import Proxy
from email import message_from_bytes

# ========== 配置你的QQ邮箱中继 ==========
RELAY_HOST = "smtp.qq.com"
RELAY_PORT = 587
RELAY_USER = "380880504@qq.com"     # QQ邮箱
RELAY_PASS = "your_auth_code"        # QQ邮箱授权码
# =======================================


class SmartRelayHandler:
    """
    智能中继处理器
    - 将收到的邮件通过真实SMTP服务器转发
    """

    def __init__(self, relay_host=None, relay_port=None, relay_user=None, relay_pass=None):
        self.relay_host = relay_host
        self.relay_port = relay_port
        self.relay_user = relay_user
        self.relay_pass = relay_pass
        self.use_relay = all([relay_host, relay_port, relay_user, relay_pass])
        self.email_count = 0

    async def handle_DATA(self, server, session, envelope):
        """处理收到的邮件并转发"""
        self.email_count += 1

        mail_from = envelope.mail_from
        rcpt_tos = envelope.rcpt_tos
        data = envelope.content

        print(f"\n{'='*70}")
        print(f"[RECEIVE] 收到邮件 #{self.email_count}")
        print(f"{'='*70}")
        print(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"发件人: {mail_from}")
        print(f"收件人: {', '.join(rcpt_tos)}")
        print(f"大小: {len(data)} bytes")

        # 解析邮件主题
        try:
            msg = message_from_bytes(data)
            subject = msg.get('Subject', 'No Subject')
            print(f"主题: {subject}")
        except:
            pass

        # 转发邮件
        if self.use_relay:
            success = self._relay_email(mail_from, rcpt_tos, data)
            if success:
                print(f"[RELAY] 邮件已通过 {self.relay_host} 转发成功")
            else:
                print(f"[FAIL] 转发失败，邮件已保存到本地")
                self._save_local(mail_from, rcpt_tos, data)
        else:
            print(f"[MODE] 本地模式 - 未配置中继，仅保存到文件")
            self._save_local(mail_from, rcpt_tos, data)

        return '250 OK'

    def _relay_email(self, mail_from, rcpt_tos, data):
        """通过真实SMTP服务器转发邮件"""
        try:
            print(f"[RELAY] 正在连接 {self.relay_host}:{self.relay_port}...")
            with smtplib.SMTP(self.relay_host, self.relay_port, timeout=30) as server:
                server.starttls()
                print(f"[RELAY] 正在登录 {self.relay_user}...")
                server.login(self.relay_user, self.relay_pass)
                print(f"[RELAY] 正在发送给 {', '.join(rcpt_tos)}...")
                server.sendmail(self.relay_user, rcpt_tos, data)
            return True
        except Exception as e:
            print(f"[RELAY ERROR] {e}")
            return False

    def _save_local(self, mail_from, rcpt_tos, data):
        """保存到本地文件"""
        try:
            with open("received_emails.log", 'a', encoding='utf-8') as f:
                f.write(f"\n{'='*70}\n")
                f.write(f"Email #{self.email_count} - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
                f.write(f"From: {mail_from}\n")
                f.write(f"To: {', '.join(rcpt_tos)}\n")
                f.write(f"{'-'*70}\n")
                f.write(data.decode('utf-8', errors='replace'))
                f.write(f"\n{'='*70}\n")
            print(f"[SAVE] 已保存到 received_emails.log")
        except Exception as e:
            print(f"[SAVE ERROR] {e}")


class DirectDeliveryHandler:
    """
    直接投递处理器
    - 尝试直接连接到收件人域名的MX记录投递
    - 大概率会被拒收（因为没有SPF/DKIM）
    """

    def __init__(self):
        self.email_count = 0

    async def handle_DATA(self, server, session, envelope):
        self.email_count += 1
        mail_from = envelope.mail_from
        rcpt_tos = envelope.rcpt_tos
        data = envelope.content

        print(f"\n{'='*70}")
        print(f"[DIRECT] 收到邮件 #{self.email_count}")
        print(f"{'='*70}")
        print(f"警告: 直接投递模式，大概率会被拒收！")
        print(f"发件人: {mail_from}")
        print(f"收件人: {', '.join(rcpt_tos)}")

        # 尝试直接投递
        for rcpt in rcpt_tos:
            domain = rcpt.split('@')[1]
            print(f"[DIRECT] 尝试投递到 {domain}...")
            try:
                # 这里简化处理，实际需要查询MX记录
                self._try_deliver(domain, mail_from, rcpt, data)
            except Exception as e:
                print(f"[DIRECT FAIL] {e}")

        # 保存备份
        with open("received_emails.log", 'a', encoding='utf-8') as f:
            f.write(f"\n[Direct Attempt] {datetime.now()}\n")
            f.write(data.decode('utf-8', errors='replace'))

        return '250 OK'

    def _try_deliver(self, domain, mail_from, rcpt_to, data):
        """尝试直接连接到目标域的邮件服务器"""
        import dns.resolver
        try:
            # 查询MX记录
            answers = dns.resolver.resolve(domain, 'MX')
            mx_host = str(answers[0].exchange)
            print(f"[DIRECT] MX记录: {mx_host}")

            # 连接并投递
            with smtplib.SMTP(mx_host, 25, timeout=10) as server:
                server.sendmail(mail_from, [rcpt_to], data)
            print(f"[DIRECT] 投递成功！")
        except Exception as e:
            print(f"[DIRECT] 投递失败: {e}")


def main():
    import argparse

    parser = argparse.ArgumentParser(description='本地SMTP中继服务器')
    parser.add_argument('--port', type=int, default=25,
                        help='本地监听端口 (默认: 25)')
    parser.add_argument('--host', type=str, default='localhost',
                        help='监听地址 (默认: localhost)')
    parser.add_argument('--relay', action='store_true',
                        help='使用中继模式 (通过QQ邮箱转发)')
    parser.add_argument('--direct', action='store_true',
                        help='使用直接投递模式 (会被拒收)')

    args = parser.parse_args()

    # 选择处理器
    if args.direct:
        handler = DirectDeliveryHandler()
        mode = "直接投递 (大概率被拒收)"
    elif args.relay:
        if RELAY_PASS == "your_auth_code":
            print("[ERROR] 请先配置QQ邮箱授权码!")
            print(f"编辑 {__file__}，修改 RELAY_PASS = '你的授权码'")
            sys.exit(1)
        handler = SmartRelayHandler(RELAY_HOST, RELAY_PORT, RELAY_USER, RELAY_PASS)
        mode = f"中继模式 (via {RELAY_HOST})"
    else:
        handler = SmartRelayHandler()  # 本地模式
        mode = "本地保存 (未配置中继)"

    # 启动服务器
    controller = Controller(handler, hostname=args.host, port=args.port)

    print("="*70)
    print(f"[SMTP Relay Server] 启动成功")
    print("="*70)
    print(f"模式: {mode}")
    print(f"监听: {args.host}:{args.port}")
    print(f"测试: python send_simple_test_email.py")
    print("-"*70)

    if args.relay:
        print(f"中继账号: {RELAY_USER}")
        print("邮件将转发到收件人邮箱")
    else:
        print("邮件仅保存到本地: received_emails.log")
        print("要启用转发，请运行: python smtp_relay_server.py --relay")

    print(f"\n按 Ctrl+C 停止服务器")
    print("="*70)

    controller.start()

    try:
        while True:
            import time
            time.sleep(1)
    except KeyboardInterrupt:
        print("\n\n正在停止服务器...")
        controller.stop()
        print("[OK] 服务器已停止")


if __name__ == '__main__':
    main()
