You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go中使用Mailtrap发送OTP邮件时TLS启动失败问题咨询

Go应用使用Mailtrap发送OTP邮件时TLS启动失败问题排查

我在Go应用中使用Mailtrap作为SMTP服务器实现用户登录的OTP邮件验证功能,但发送邮件时遇到如下TLS相关错误:

Generated OTP: 570528
Sending OTP email to: adebayoodukoya@yahoo.com
Error sending OTP email: failed to start TLS: 421 Local Error, closing transmission channel

相关代码片段

调用发送邮件的代码

// Send OTP email
err := sendOTPEmail(user.Email, otp)
if err != nil {
    fmt.Println("Error sending OTP email:", err)
    c.Status(http.StatusInternalServerError)
    return c.JSON(fiber.Map{
        "error": "Error sending OTP",
    })
}

sendOTPEmail函数实现

func sendOTPEmail(email, otp string) error {
    // Connect to the SMTP server
    client, err := smtp.Dial(smtpHost + ":" + strconv.Itoa(smtpPort))
    if err != nil {
        return fmt.Errorf("failed to connect to SMTP server: %v", err)
    }
    defer client.Close()

    // Start TLS encryption
    if err := client.StartTLS(nil); err != nil {
        return fmt.Errorf("failed to start TLS: %v", err)
    }

    // Authentication
    auth := smtp.PlainAuth("", smtpUser, smtpPassword, smtpHost)
    if err := client.Auth(auth); err != nil {
        return fmt.Errorf("authentication failed: %v", err)
    }

    // Compose the email message
    subject := "Your OTP for sign-in"
    body := fmt.Sprintf("Your OTP (One-Time Password) for sign-in is: %s", otp)
    msg := []byte("To: " + email + "\r\n" +
        "Subject: " + subject + "\r\n" +
        "\r\n" +
        body)

    // Send the email
    if err := client.Mail(smtpUser); err != nil {
        return fmt.Errorf("failed to send MAIL command: %v", err)
    }
    if err := client.Rcpt(email); err != nil {
        return fmt.Errorf("failed to send RCPT command: %v", err)
    }
    w, err := client.Data()
    if err != nil {
        return fmt.Errorf("failed to open data writer: %v", err)
    }
    defer w.Close()

    _, err = w.Write(msg)
    if err != nil {
        return fmt.Errorf("failed to write email body: %v", err)
    }

    return nil
}

问题原因与解决方法

核心原因1:端口与连接方式不匹配

Mailtrap的SMTP端口对应不同的加密策略,错误的端口搭配会触发TLS错误:

  • 25/2525:明文端口,无需调用StartTLS
  • 465:SSL/TLS端口,需直接建立加密连接,不能先明文连接再启动TLS
  • 587:STARTTLS端口,适合先明文连接再升级为TLS加密

核心原因2:TLS配置缺失

原代码中StartTLS(nil)使用空配置,无法正确验证Mailtrap的服务器证书,导致握手失败。


针对性解决方法

场景1:使用推荐的587端口(STARTTLS)

确保smtpPort设置为587,修改StartTLS调用,添加正确的TLS配置:

// 替换原StartTLS代码
config := &tls.Config{ServerName: smtpHost}
if err := client.StartTLS(config); err != nil {
    return fmt.Errorf("failed to start TLS: %v", err)
}

ServerName必须设置,否则会触发证书域名不匹配的验证错误。

场景2:使用465端口(SSL/TLS)

直接通过TLS建立连接,替换原smtp.Dial代码:

// 替换原smtp.Dial部分
addr := fmt.Sprintf("%s:%d", smtpHost, smtpPort)
tlsConfig := &tls.Config{ServerName: smtpHost}
conn, err := tls.Dial("tcp", addr, tlsConfig)
if err != nil {
    return fmt.Errorf("failed to connect to SMTP server over TLS: %v", err)
}
client, err := smtp.NewClient(conn, smtpHost)
if err != nil {
    return fmt.Errorf("failed to create SMTP client: %v", err)
}
defer client.Close()
// 此处无需再调用StartTLS,直接执行认证步骤

场景3:使用25/2525端口(明文,仅测试用)

删除StartTLS相关代码,直接进行认证,但此方式不安全,不建议生产环境使用。

额外优化建议

  • 确认smtpHost为Mailtrap提供的准确地址(如smtp.mailtrap.io)
  • 邮件头部添加From字段,避免被标记为垃圾邮件:
msg := []byte("From: Your App Name <" + smtpUser + ">\r\n" +
    "To: " + email + "\r\n" +
    "Subject: " + subject + "\r\n" +
    "\r\n" +
    body)

内容的提问来源于stack exchange,提问作者Abdullah odukoya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:37:40