V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
tiRolin
V2EX  ›  Java

使用 SMTP 协议发送邮件问题求教,我自己是真解决不了

  •  
  •   tiRolin · 2025 年 5 月 19 日 · 3993 次点击
    这是一个创建于 242 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在有要求如下

    websocket 连接/smtp 端点,模拟 SMTP 协议发送邮件,发件地址: [email protected] ,收件地址 [email protected] ,邮件内容 Hello World 。请注意:大小写敏感,websocket 连接仅保留 1 分钟左右,断了需要重连并重头发送 SMTP 命令

    可以确定发送的地址是 wss://interview-test.nullht.com/smtp

    我按照他的要求,写出了下面的代码,其他的不重要,我们直接看我发送请求的格式

        private void initializeCommands() {
            commandQueue.clear();
            commandQueue.add("EHLO mine.com\r\n");
            commandQueue.add("MAIL FROM:<[email protected]>\r\n");
            commandQueue.add("RCPT TO:<[email protected]>\r\n");
            commandQueue.add("DATA\r\n");
            // 注意:邮件内容需要包含完整格式
            commandQueue.add(
                "From: [email protected]\r\n" +
                    "To: [email protected]\r\n" +
                    "Subject: Hello\r\n" +
                    "\r\n" +  // 空行分隔头部和正文
                    "Hello World\r\n" +
                    ".\r\n"    // 结束符
            );
            commandQueue.add("QUIT\r\n");
        }
    

    这个代码可以得到下面的响应:

    Sending command: EHLO mine.com
    Server response: 220 邮件服务器准备就绪
    Server response: 250 很高兴认识你
    Sending command: MAIL FROM:<[email protected]>
    Server response: 250 发件人已接受
    Sending command: RCPT TO:<[email protected]>
    Server response: 250 收件人已接受
    Sending command: DATA
    Server response: 500 命令不被识别
    

    显然是 DATA 后的内容有问题,其他的都没毛病。但是我参照下面的教程

    https://blog.csdn.net/weixin_39833509/article/details/88965720

    感觉这个格式也没问题啊,我试了好久了都没搞出来到底哪里有问题,什么 AI 、谷歌全试过了,有没有大佬救一下,小弟我是真不行了,我先谢谢各位了

    26 条回复    2025-05-20 16:27:48 +08:00
    lemonda
        1
    lemonda  
       2025 年 5 月 19 日
    不懂,但是以前排查过一个收不到信的情况,看看 DATA 的邮件模板是 CRLF 还是 LF
    phrack
        2
    phrack  
       2025 年 5 月 19 日
    这也太底层了,email 的协议又很古老复杂,现在不都是用第三方发信直接 rest api 就完了,第三方帮你屏蔽了底层细节了。
    poxiaogg
        3
    poxiaogg  
       2025 年 5 月 19 日
    不需要\r\n 结尾
    ```
    commandQueue.add("DATA");
    ```
    bingfengfeifei
        5
    bingfengfeifei  
       2025 年 5 月 19 日
    看了下 Suricata 解析 smtp 的代码,看上去没问题啊 说不定是服务器实现有问题
    tiRolin
        6
    tiRolin  
    OP
       2025 年 5 月 19 日
    @bingfengfeifei 服务器不太可能有问题,因为这个服务器不是我的,而是公司提供的
    ZiLong
        7
    ZiLong  
       2025 年 5 月 19 日
    捞服务器日志看下,有可能错的是服务器实现呢
    hefish
        8
    hefish  
       2025 年 5 月 19 日
    \r\n 改成 \n\r 看看。。
    这个协议会话没问题。 我 20 年前搞邮件服务器时候,手动 telnet 25 测试发信也是这么输入的。
    gesse
        9
    gesse  
       2025 年 5 月 20 日
    是不是先要验证——执行“AUTH LOGIN\r\n”命令?
    daxy223
        10
    daxy223  
       2025 年 5 月 20 日
    yinmin
        11
    yinmin  
       2025 年 5 月 20 日 via iPhone
    用 gpt 或 claude 写一个 websocket to tcp 的桥接程序,还原出 smtp ,然后用 java 内置的发邮件功能试试。

    自己手搓基于邮件协议的代码,中文编码、html 邮件、附件功能都是有工作量的。
    yinmin
        12
    yinmin  
       2025 年 5 月 20 日 via iPhone
    你可以问问公司是否能提供 smtp ( 25 端口)或者 smtps ( 465 端口),可以直接用 java 内置的发邮件功能;或者是否提供高级的邮件 api ,输入 from 、to 、subject 、mailbody 能直接发邮件。

    基于 smtp 协议让员工手搓,感觉有点扯了。
    jason56
        13
    jason56  
       2025 年 5 月 20 日
    估计是服务端需要验证,试试 AUTH LOGIN / USER /PASS
    gtese
        14
    gtese  
       2025 年 5 月 20 日
    去问下服务器是不是支持匿名,看看匿名怎么写, 如果是需要验证,再去找下验证怎么写。
    smtp 出故障的时候,用 telnet 一条条命令试。试成了再去用代码。
    hytex
        15
    hytex  
       2025 年 5 月 20 日
    这个已经玩过了,直接给你发结果
    import asyncio
    import websockets

    async def send_smtp_commands():
    uri = "wss://interview-test.nullht.com/smtp" # 根据实际情况修改为 wss:// 或 ws://

    try:
    async with websockets.connect(uri) as websocket:
    # 等待服务器欢迎语(类似于 220 开头的回应)
    print(await websocket.recv())

    # 按照 SMTP 协议逐步发送命令
    await websocket.send("HELO localhost")
    print(await websocket.recv())

    await websocket.send("MAIL FROM:<[email protected]>")
    print(await websocket.recv())

    await websocket.send("RCPT TO:<[email protected]>")
    print(await websocket.recv())

    await websocket.send("DATA")
    print(await websocket.recv())

    await websocket.send("Hello World")
    # print(await websocket.recv())


    await websocket.send(".")
    print(await websocket.recv())


    await websocket.send("QUIT")
    print(await websocket.recv())

    except Exception as e:
    print(f"连接或发送失败: {e}")

    asyncio.run(send_smtp_commands())
    hytex
        16
    hytex  
       2025 年 5 月 20 日
    @hytex 自己格式化一下 0.0
    lucasdev
        17
    lucasdev  
       2025 年 5 月 20 日
    宇宙的终极最终答案:42
    是因为这个服务器“只识别单行命令的,要一行行发送,包括最后的.” 参考 https://linux.do/t/topic/638484/24

    都从哪看到的这个
    jackOff
        18
    jackOff  
       2025 年 5 月 20 日
    就这么说吧,写邮件的第三方库都没几个在认真维护,我蹲一个 email.message_from_bytes 的内存爆炸问题都等了好几年了今年才有热心网友愿意自己优化设计,https://github.com/python/cpython/issues/115512
    pulutom40
        19
    pulutom40  
       2025 年 5 月 20 日 via iPhone
    什么鬼? smtp 协议是基于 tcp 的,websocket 是什么鬼? ws 的话就不是原始的 smtp 协议了,这种出问题要问提供给你 ws 协议的服务方。只看 smtp 命令的话没啥问题,你可以使用 telnet 模拟客户端给 gmail 发信测试
    pulutom40
        20
    pulutom40  
       2025 年 5 月 20 日 via iPhone
    另外,你都不是基于 tcp 在投件,那你应该是需要发件吧?发件一般是需要先登录的
    teaser
        21
    teaser  
       2025 年 5 月 20 日
    别在代码里测试了,直接 telnet 模拟发送测试吧
    unused
        22
    unused  
       2025 年 5 月 20 日
    等服务器回复再发下一条
    0x663
        23
    0x663  
       2025 年 5 月 20 日
    好奇基于 websocket 协议的邮件是什么样的
    dreamage
        24
    dreamage  
       2025 年 5 月 20 日
    smtp 套 wss 什么骚操作
    tiRolin
        25
    tiRolin  
    OP
       2025 年 5 月 20 日
    @dreamage 我不太懂,所以我是直接通过 AI 写的,我也不知道该怎么办,他这个问题我之前都没接触过
    julyclyde
        26
    julyclyde  
       2025 年 5 月 20 日
    smtp 协议没问题
    不过你得先问问这个 smtp 是不是需要先 auth
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   2608 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 10:57 · PVG 18:57 · LAX 02:57 · JFK 05:57
    ♥ Do have faith in what you're doing.