ASP.NET Core MVC表单发邮件报ArgumentNullException:原因与解决
我在ASP.NET Core MVC项目中开发联系表单发送邮件功能,运行时抛出ArgumentNullException: Value cannot be null. (Parameter 'address')错误,相关代码及报错信息如下:
相关代码
模型类(SendMail.cs)
public class SendMail : IEmailSender { public async Task SendEmailAsync(string email, string subject, string htmlMessage) { using (MailMessage mailMessage = new MailMessage()) { mailMessage.From = new MailAddress(email); mailMessage.Subject = subject; mailMessage.Body = email + htmlMessage; mailMessage.IsBodyHtml = true; mailMessage.To.Add(new MailAddress("abc@gmail.com")); SmtpClient smtp = new SmtpClient(); smtp.Host = "smtp.gmail.com"; smtp.EnableSsl = true; System.Net.NetworkCredential NetworkCred = new System.Net.NetworkCredential(); NetworkCred.UserName = "abc@gmail.com"; NetworkCred.Password = "cxhzevbomlrgebrb"; smtp.UseDefaultCredentials = true; smtp.Credentials = NetworkCred; smtp.Port = 587; await smtp.SendMailAsync(mailMessage); } } }
视图(Contact.cshtml)
@model eProject3_6.ViewModel.Contact; <div class="row"> <div class="eight columns"> <!-- form --> <form method="post"> <fieldset> <div> <label asp-for="Email">Email <span class="required">*</span></label> <input asp-for="Email" type="text" value="" size="35" id="contactEmail" name="contactEmail"> <span asp-validation-for="Email" class="text-danger"></span> </div> <div> <label asp-for="Subject">Subject</label> <input asp-for="Subject" type="text" value="" size="35" id="contactSubject" name="contactSubject"> <span asp-validation-for="Subject" class="text-danger"></span> </div> <div> <label asp-for="Message">Message <span class="required">*</span></label> <textarea asp-for="Message" cols="50" rows="15" id="contactMessage" name="contactMessage"></textarea> <span asp-validation-for="Message" class="text-danger"></span> </div> <div> <button class="submit">Submit</button> <span id="image-loader"> <img alt="" src="~/ContactForm/images/loader.gif"> </span> </div> </fieldset> </form> <!-- Form End --> </div>
控制器类(HomeController.cs)
[HttpGet] public IActionResult Contact() { return View(); } [HttpPost] public async Task<IActionResult> Contact(Contact contact) { var msg = contact.Subject + "" + contact.Message; await _emailSender.SendEmailAsync(contact.Email, "Contact Message", msg); ViewBag.Message = "Thank for your contact"; return View(); }
ViewModel类(Contact.cs)
public class Contact { public string Email { get ; set ; } public string Subject { get; set; } public string Message { get; set; } }
报错信息
ArgumentNullException: Value cannot be null. (Parameter 'address')
System.Net.Mail.MailAddress.TryParse(string address, string displayName, Encoding displayNameEncoding, out ValueTuple<string, string, string, Encoding> parsedData, bool throwExceptionIfFail)
System.Net.Mail.MailAddress..ctor(string address)
eProject3_6.Models.SendMail.SendEmailAsync(string email, string subject, string htmlMessage) in SendMail.cs
mailMessage.From = new MailAddress(email);
eProject3_6.Controllers.HomeController.Contact(Contact contact) in HomeController.cs
await _emailSender.SendEmailAsync(contact.Email, "Contact Message", msg);
...(后续调用栈省略)
错误原因
- 模型绑定失败:视图中手动指定
name="contactEmail"等属性,覆盖了asp-for生成的与ViewModel字段匹配的name值,导致表单提交时contact.Email无法被正确赋值,最终传入SendEmailAsync的参数为null。 - 缺少数据验证:ViewModel未添加必填验证特性,用户即使不填Email也能提交表单,触发空值错误。
- SMTP逻辑错误:直接将用户输入的Email作为发件人地址,不符合Gmail SMTP服务要求(发件人必须与认证邮箱一致),同时
smtp.UseDefaultCredentials = true会覆盖后续设置的认证信息,导致SMTP认证失败。
解决步骤
1. 修复模型绑定问题
移除视图中手动设置的name属性,让asp-for自动生成匹配ViewModel字段的name值:
<!-- 修正后的Email输入框 --> <input asp-for="Email" type="text" value="" size="35" id="contactEmail"> <!-- 修正后的Subject输入框 --> <input asp-for="Subject" type="text" value="" size="35" id="contactSubject"> <!-- 修正后的Message文本框 --> <textarea asp-for="Message" cols="50" rows="15" id="contactMessage"></textarea>
2. 添加数据验证到ViewModel
给ViewModel字段添加验证特性,强制用户填写必填项:
using System.ComponentModel.DataAnnotations; public class Contact { [Required(ErrorMessage = "请输入邮箱地址")] [EmailAddress(ErrorMessage = "请输入有效的邮箱地址")] public string Email { get ; set ; } public string Subject { get; set; } [Required(ErrorMessage = "请输入消息内容")] public string Message { get; set; } }
3. 完善控制器验证逻辑
在Post方法中先检查模型有效性,无效则返回视图显示错误:
[HttpPost] public async Task<IActionResult> Contact(Contact contact) { if (!ModelState.IsValid) { return View(contact); } var msg = $"发件人邮箱:{contact.Email}\n主题:{contact.Subject}\n消息:{contact.Message}"; await _emailSender.SendEmailAsync(contact.Email, "Contact Message", msg); ViewBag.Message = "感谢您的联系"; return View(); }
4. 修正SendMail中的SMTP配置
- 发件人地址改为SMTP认证邮箱,将用户邮箱设为回复地址
- 调整
UseDefaultCredentials顺序,避免覆盖认证信息:
public async Task SendEmailAsync(string email, string subject, string htmlMessage) { using (MailMessage mailMessage = new MailMessage()) { // 发件人必须与SMTP认证邮箱一致 mailMessage.From = new MailAddress("abc@gmail.com"); // 设置回复地址为用户邮箱 mailMessage.ReplyToList.Add(new MailAddress(email)); mailMessage.Subject = subject; mailMessage.Body = htmlMessage; mailMessage.IsBodyHtml = false; // 纯文本消息更稳定,如需HTML可改为true mailMessage.To.Add(new MailAddress("abc@gmail.com")); SmtpClient smtp = new SmtpClient(); smtp.Host = "smtp.gmail.com"; smtp.EnableSsl = true; System.Net.NetworkCredential NetworkCred = new System.Net.NetworkCredential(); NetworkCred.UserName = "abc@gmail.com"; NetworkCred.Password = "cxhzevbomlrgebrb"; // 先关闭默认凭证,再设置自定义凭证 smtp.UseDefaultCredentials = false; smtp.Credentials = NetworkCred; smtp.Port = 587; await smtp.SendMailAsync(mailMessage); } }
5. 额外配置注意
- 若Gmail账户开启了两步验证,需使用应用专用密码替代原密码
- 若未开启两步验证,需在Gmail账户设置中开启"低安全性应用访问"(或使用更安全的OAuth2认证)
内容的提问来源于stack exchange,提问作者Noo

