代码之家  ›  专栏  ›  技术社区  ›  Stefan0309

如何正确地-异步地发送电子邮件?邮件从不到达

  •  1
  • Stefan0309  · 技术社区  · 6 年前

    我在C_中创建了一个新的MVC5项目。

    我有一些模型:

    public class EmailFormModel
    {
        [Required, Display(Name = "Your name")]
        public string FromName { get; set; }
        [Required, Display(Name = "Your email"), EmailAddress]
        public string FromEmail { get; set; }
        [Required]
        public string Message { get; set; }
    }
    

    我有一个conctact.cshtml:

    @model EMailSenderWebApp.Models.EmailFormModel
    @{
        ViewBag.Title = "Contact";
    }
    <h2>@ViewBag.Title.</h2>
    
    @using (Html.BeginForm("SendEmailAsync", "Home", FormMethod.Post, new { role = "form contact-form", @id = "form-div" }))
    {
        @Html.AntiForgeryToken()
        <h4>Send your comments.</h4>
        <hr />
        <div class="form-group">
            @Html.LabelFor(m => m.FromName, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(m => m.FromName, new { @class = "form-control" })
                @Html.ValidationMessageFor(m => m.FromName)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(m => m.FromEmail, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(m => m.FromEmail, new { @class = "form-control" })
                @Html.ValidationMessageFor(m => m.FromEmail)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(m => m.Message, new { @class = "col-md-2 control-label"  })
            <div class="col-md-10">
                @Html.TextAreaFor(m => m.Message, new { @class = "form-control" })
                @Html.ValidationMessageFor(m => m.Message)
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" class="btn btn-default" value="Send" />
            </div>
        </div>
    }
    
    @section Scripts {
        @Scripts.Render("~/bundles/jqueryval")
    }
    

    因此,如您所见,我的表单调用httppost方法“sendmailasync”,如我的主控制器中所述:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult SendEmailAsync(EmailFormModel model)
    {
        if (ModelState.IsValid)
        {
            SmtpClient client = new SmtpClient();
    
            MailMessage message = new MailMessage();
            var body = "<p>Email From: {0} ({1})</p><p>Message:</p><p>{2}</p>";
            message.To.Add(new MailAddress("stefan.cv5@gmail.com"));  // replace with valid value 
            message.From = new MailAddress("stefan.cv5@gmail.com");  // replace with valid value
            message.Subject = "Your email subject";
            message.Body = string.Format(body, model.FromName, model.FromEmail, model.Message);
            message.IsBodyHtml = true;
    
            client.Credentials = new NetworkCredential("", "");
            client.Host = "smtp.gmail.com";
            client.Port = 587;
            client.EnableSsl = false;
    
            client.SendCompleted += (s, e) =>
            {
                client.Dispose();
                message.Dispose();
    
            };
            ThreadPool.QueueUserWorkItem(o =>
                client.SendAsync(message, Tuple.Create(client, message)));
        }
        return View(model);
    }
    

    我试过一些例子

    等待客户端。SendMailSync() 但正如您可能知道的,异步调用不存在,并且永远不会返回(关于这个的更多信息 here )

    所以,我已经这样实现了 this stack-overflow article

    这会一直执行方法(在最后返回视图),但我的电子邮件永远不会进入我的收件箱?

    也许谷歌有防火墙?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Neil    6 年前

    这里发生的事情是您从未将您的SMTP客户端连接到服务器。通常这会引发异常,但是您也试图在线程池工作进程中发送邮件,而没有正确的try/catch。没有任何代码可以捕获异常,因此似乎什么都没有发生。

    也可以在下面看到我的编辑 SmtpClient MailMessage 里面 using 块以便您不必手动调用 .Dispose() . 这确保即使在连接或发送消息时发生异常,也会释放资源。

    正如其他人提到的,内置的system.net.mail库不再维护。我建议使用 MailKit ( nuget link )因为它保养得非常好,而且车主的反应也非常灵敏。

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> SendEmailAsync(EmailFormModel model)
    {
        if (ModelState.IsValid)
        {
            // Create IDisposable inside `using` block so you aren't on the hook for calling Dispose()
            // The same has been done with your MailMessage
            using(SmtpClient client = new SmtpClient())
            {
                client.Credentials = new NetworkCredential("", "");
                client.Host = "smtp.gmail.com";
                client.Port = 587;
                client.EnableSsl = false;
    
                // You were missing this before which
                // was causing the exception. But due
                // to the thread your email was sent from
                // the exception was not thrown from a context
                // where you could know about it at all.
                await client.ConnectAsync();
    
                using(MailMessage message = new MailMessage())
                {
                    var body = "<p>Email From: {0} ({1})</p><p>Message:</p><p>{2}</p>";
                    message.To.Add(new MailAddress("stefan.cv5@gmail.com"));  // replace with valid value 
                    message.From = new MailAddress("stefan.cv5@gmail.com");  // replace with valid value
                    message.Subject = "Your email subject";
                    message.Body = string.Format(body, model.FromName, model.FromEmail, model.Message);
                    message.IsBodyHtml = true;
    
                    await client.SendAsync(message);
                }
            }
        }
    
        return View(model);
    }