ASP.NET MVC Send email using SendAsync System.Net.Mail
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Sending email from an ASP.NET MVC application should not block the request thread longer than necessary. That is why developers look at System.Net.Mail asynchronous APIs. The important detail is that there are two patterns in this namespace: the older event-based SendAsync API and the more modern task-based SendMailAsync API. In MVC code, the task-based form is usually the better choice.
Why SendAsync Feels Awkward in MVC
SmtpClient.SendAsync predates async and await. It uses an event callback model where you subscribe to completion events and track state manually. That style works, but it is harder to compose with controller actions, error handling, and cancellation in modern ASP.NET code.
By contrast, SendMailAsync returns a task, which fits naturally into controller methods.
A Practical MVC Example
Here is a simple service class using SendMailAsync:
Then call it from a controller action:
This keeps the controller readable and lets exceptions flow through normal async error handling.
What If You Must Use SendAsync
If you are maintaining older code and need the event-based API, it looks more like this:
The problem is not that this never works. The problem is that lifetime management, completion handling, and exception flow are more fragile in request-driven web applications.
Request Flow and Reliability
Even when using async email APIs, think carefully about whether the email must be sent before the HTTP response completes. For account registration, a brief await may be acceptable. For high-volume notifications, a background queue is often better.
That design choice matters more than the specific API name. The email operation is still dependent on:
- SMTP server availability
- network latency
- authentication success
- retry strategy
If the email is business-critical but not user-blocking, enqueue the work and let a background processor send it.
Exception Handling and Resource Disposal
With MailMessage and SmtpClient, dispose objects deterministically. Using using blocks or using var avoids leaking sockets or message resources.
Also surface meaningful errors. SMTP failures are often operational issues rather than coding errors, so log:
- host and port used
- recipient domain
- authentication failures
- timeout behavior
Do not return raw SMTP exceptions to end users.
About System.Net.Mail Today
System.Net.Mail still exists and can be fine for straightforward scenarios, especially in older ASP.NET MVC applications. But for new systems that need richer protocol support, better testing hooks, or more modern features, many teams choose dedicated libraries or API-based mail providers.
That does not invalidate SendMailAsync. It just means you should not mistake "works in development" for "good enough for production-scale mail delivery."
Common Pitfalls
A frequent mistake is using SendAsync in MVC and assuming the request lifecycle will naturally manage completion. It will not. You still need to think about disposal, completion, and failures.
Another issue is creating a fire-and-forget email task inside a controller and returning immediately. That can hide exceptions and produce unreliable delivery.
Developers also sometimes forget SMTP configuration details such as TLS requirements, sender permissions, or provider throttling limits.
Finally, avoid hardcoding secrets in source files. Pull SMTP credentials from configuration or a secret store.
Summary
- In ASP.NET MVC, prefer
SendMailAsyncover the older event-basedSendAsync. - '
SendAsyncworks, but it is awkward to manage in modern controller code.' - Dispose
MailMessageandSmtpClientcarefully. - Decide whether sending email belongs in the request path or in a background queue.
- Treat SMTP delivery as an operational dependency, not just a code snippet.
- For new systems with heavier requirements, consider more modern email delivery approaches.

