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

C# .NET Core Web API中SMTP邮件发送状态数据库记录方案咨询

解决思路与实现步骤

1. 设计邮件状态追踪表

先在数据库中创建专门用于记录邮件发送状态的表,核心字段需覆盖关键追踪信息:

  • 主键ID(如EmailLogId)
  • 收件人邮箱(RecipientEmail)
  • 邮件主题(Subject)
  • 邮件内容摘要(ContentSummary,可选,若需存完整内容也可调整)
  • 发送状态(Status,用枚举定义:Pending/Sending/Success/Failed)
  • 错误详情(ErrorMessage,发送失败时存储异常信息)
  • 请求创建时间(CreatedAt)
  • 发送完成时间(SentAt,成功/失败后更新)

用EF Core的话,可定义对应的实体类:

public enum EmailStatus
{
    Pending,
    Sending,
    Success,
    Failed
}

public class EmailLog
{
    public int EmailLogId { get; set; }
    public string RecipientEmail { get; set; } = string.Empty;
    public string Subject { get; set; } = string.Empty;
    public string? ContentSummary { get; set; }
    public EmailStatus Status { get; set; }
    public string? ErrorMessage { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public DateTime? SentAt { get; set; }
}

2. 封装SMTP发送与状态更新逻辑

创建独立的邮件服务类,整合发送逻辑与数据库状态记录,避免业务代码混杂细节:

public class EmailService
{
    private readonly SmtpClient _smtpClient;
    private readonly AppDbContext _dbContext;

    public EmailService(SmtpClient smtpClient, AppDbContext dbContext)
    {
        _smtpClient = smtpClient;
        _dbContext = dbContext;
    }

    public async Task SendAndLogEmailAsync(string toEmail, string subject, string body)
    {
        // 1. 插入待发送记录
        var emailLog = new EmailLog
        {
            RecipientEmail = toEmail,
            Subject = subject,
            ContentSummary = body.Length > 200 ? body[..200] + "..." : body,
            Status = EmailStatus.Pending
        };
        _dbContext.EmailLogs.Add(emailLog);
        await _dbContext.SaveChangesAsync();

        try
        {
            // 2. 更新为发送中状态
            emailLog.Status = EmailStatus.Sending;
            await _dbContext.SaveChangesAsync();

            // 3. 执行SMTP发送
            var mailMessage = new MailMessage("your-sender@domain.com", toEmail, subject, body);
            await _smtpClient.SendMailAsync(mailMessage);

            // 4. 发送成功,更新状态与完成时间
            emailLog.Status = EmailStatus.Success;
            emailLog.SentAt = DateTime.UtcNow;
        }
        catch (SmtpException ex)
        {
            // 5. 发送失败,记录错误信息
            emailLog.Status = EmailStatus.Failed;
            emailLog.ErrorMessage = ex.Message + (ex.InnerException != null ? $" | {ex.InnerException.Message}" : "");
            emailLog.SentAt = DateTime.UtcNow;
        }
        finally
        {
            await _dbContext.SaveChangesAsync();
        }
    }
}

SMTP客户端可通过配置文件注入,在Program.cs中注册:

builder.Services.AddTransient<SmtpClient>(sp =>
{
    var config = sp.GetRequiredService<IConfiguration>();
    return new SmtpClient(config["Smtp:Server"])
    {
        Port = int.Parse(config["Smtp:Port"]),
        Credentials = new NetworkCredential(config["Smtp:Username"], config["Smtp:Password"]),
        EnableSsl = bool.Parse(config["Smtp:EnableSsl"])
    };
});
builder.Services.AddTransient<EmailService>();

3. 异步发送优化(可选但推荐)

若API请求量较大,同步发送会阻塞请求拖慢响应。可将发送逻辑放到后台处理:

  • 用IHostedService实现后台任务,定时拉取数据库中Pending状态的邮件,执行发送并更新状态
  • 或使用Hangfire等任务调度库,将发送任务加入队列,后台异步执行

这样API仅需创建待发送记录即可返回响应,提升用户体验。

4. 处理SMTP接收后的“软失败”

SMTP返回成功仅代表邮件被发送方服务器接收,不保证能送达用户邮箱(如收件人不存在、被反垃圾系统拦截)。若需更精准状态:

  • 配置发送邮箱的退回通知(Bounce Notification),让服务器将无法投递的邮件转发至监控邮箱
  • 编写后台服务定时读取监控邮箱,解析退回邮件(如RFC 3464格式),找到对应邮件记录并更新状态为Failed,补充退回原因

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:52:37