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

.NET Core 6 API部署远程Ubuntu Docker无法发邮件求助

问题诊断与修复方案

一、代码中的明显错误

1. SSL配置矛盾

你代码中enableSsl设为true,但ConnectAsync的第三个参数传的是false,这会导致SSL/TLS配置不匹配。对于587端口,通常使用STARTTLS模式,正确的做法是先以非SSL连接,再调用StartTlsAsync启用加密,或者直接匹配参数。

2. 附件处理逻辑错误

你在添加附件时使用了new Attachment(stream, attachment.Key).ToString(),这完全错误——Attachment.ToString()只会返回对象的类型名称,不会添加实际的附件内容。应该直接通过BodyBuilder的Attachments.Add方法传入流和文件名。

3. 异常处理掩盖真实错误

catch块中抛出new Exception("err", ex),可能导致上层代码无法正确捕获原始异常的详细信息,让你误以为“无错误提示”。应该直接抛出原始异常,或者记录完整的异常日志。

二、修复后的代码示例

public async Task SendMailAsync(string email, string body, string subject, Dictionary<string, byte[]> attachments)
{
    var settings = _appSettings.Value;
    string smtpHost = settings.MailHost; // mail.kurumsaleposta.com
    int smtpPort = settings.MailPort; // 587
    string smtpUsername = settings.MailUsername;
    string smtpPassword = settings.MailPassword;
    string displayName = settings.MailDisplayName;
    bool enableSsl = true;

    try
    {
        var message = new MimeMessage();
        message.From.Add(new MailboxAddress(displayName, smtpUsername));
        message.To.Add(new MailboxAddress("", email)); 
        message.Subject = subject;

        var bodyBuilder = new BodyBuilder();
        string bodysablon = File.ReadAllText("MailTemplate/MailTemplate.html");
        var sablon = bodysablon.Replace("[MailTemplate]", body);
        bodyBuilder.HtmlBody = sablon;
        bodyBuilder.TextBody = "";

        // 先处理附件,再生成消息体(原代码顺序错误,附件不会被加入message)
        if (attachments != null && attachments.Count > 0)
        {
            foreach (var attachment in attachments)
            {
                using var stream = new MemoryStream(attachment.Value);
                bodyBuilder.Attachments.Add(attachment.Key, stream);
            }
        }

        message.Body = bodyBuilder.ToMessageBody();

        using var client = new MailKit.Net.Smtp.SmtpClient();
        // 启用调试日志,方便排查问题(生产环境可关闭)
        client.Logger = new ProtocolLogger(Console.OpenStandardError());
        client.ServerCertificateValidationCallback = (s, c, h, e) => true;

        // 针对587端口使用STARTTLS模式
        await client.ConnectAsync(smtpHost, smtpPort, SecureSocketOptions.StartTls);
        await client.AuthenticateAsync(smtpUsername, smtpPassword);
        await client.SendAsync(message);
        await client.DisconnectAsync(true);
    }
    catch (Exception ex)
    {
        // 记录完整异常日志(比如用ILogger),再抛出原始异常
        // _logger.LogError(ex, "发送邮件失败");
        throw; // 直接抛出原始异常,保留完整调用栈和错误信息
    }
}

三、远程Docker容器的环境排查

1. 网络连通性测试

进入远程Docker容器内部,执行以下命令测试SMTP服务器的连通性:

# 测试端口是否可达
telnet mail.kurumsaleposta.com 587
# 或用nc命令(如果容器内没有telnet)
nc -zv mail.kurumsaleposta.com 587

如果连接失败,说明远程服务器的防火墙/安全组封禁了587端口的出站请求,需要联系服务器管理员开放该端口。

2. DNS解析验证

在容器内执行DNS解析测试,确认能正确解析SMTP服务器地址:

nslookup mail.kurumsaleposta.com

如果解析失败,需要检查Docker容器的DNS配置,或者在容器中手动指定DNS服务器(比如8.8.8.8)。

3. SMTP服务器IP白名单

部分邮件服务商(尤其是企业邮箱)会限制发送IP的白名单,确认远程服务器的公网IP已被添加到SMTP服务商的允许列表中。

4. 查看容器日志

确保你的API项目开启了日志输出,查看Docker容器的日志,获取异常的详细信息:

docker logs <你的容器ID/名称>

内容的提问来源于stack exchange,提问作者Oguz Demirel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 01:08:31