C# send email with attachment with working code example.

In this blog post, I will show you how to send email with attachments using ASP.NET MVC and you can also download the working example from GitHub.

This code also shows you how to use a partial view as an email template for your emails.

It does not show you how to post the form using jQuery, but that could be another post.

As usual, let's get straight into the code and create the view for submitting the form as can be seen below.

@model Web.Model.EmailAttachmentModel.EmailBodyViewModel

@using (Html.BeginForm("SendEmail", "SendEmail", FormMethod.Post, new { id = "frmContact", name = "frmContact", novalidate = "novalidate" }))
{
    @Html.AntiForgeryToken()
    <div class="container">
        @if (TempData["ErrorList"] != null)
        {
            <div class="row">
                <div class="col-12">
                    <h2>Please fix the errors below</h2>
                    @Html.Raw(TempData["ErrorList"].ToString())
                </div>
            </div>
        }
        <div class="row">
            <div class="col-12">
                <form method="post" action="/" id="demoValidation" name="demoValidation">
                    <div class="form-group">
                        @Html.LabelFor(x => x.Email)
                        @Html.TextBoxFor(x => x.Email, new { @class = "form-control", placeholder = "Email" })
                        @Html.ValidationMessageFor(x=>x.Email)
                    </div>
                    <div class="form-group">
                        @Html.LabelFor(x => x.Name)
                        @Html.TextBoxFor(x => x.Name, new { @class = "form-control", placeholder = "Name" })
                        @Html.ValidationMessageFor(x => x.Name)
                    </div>
                    <div class="form-group">
                        @Html.LabelFor(x => x.Subject)
                        @Html.TextBoxFor(x => x.Subject, new { @class = "form-control", placeholder = "Subject" })
                        @Html.ValidationMessageFor(x => x.Subject)
                    </div>
                    <div class="form-group">
                        @Html.LabelFor(x => x.Message)
                        @Html.TextAreaFor(x => x.Message, new { @class = "form-control", placeholder = "Message" })
                        @Html.ValidationMessageFor(x => x.Message)
                    </div>
                    <div class="form-group">
                        <button class="btn btn-success" type="submit"> Send <i class="fa fa-chevron-circle-right"></i></button>
                    </div>
                </form>
            </div>
        </div>
    </div>
}

View Model.

The ViewModel for the validation can be seen below. 

using System.ComponentModel.DataAnnotations;

namespace Web.Model.EmailAttachmentModel
{
    public class EmailBodyViewModel
    {
        [Required(ErrorMessage = "Email Required")]
        public string Email { get;set; }
        [Required(ErrorMessage = "Name Required")]
        public string Name { get; set; }
        [Required(ErrorMessage = "Subject Required")]
        public string Subject { get; set; }
        [Required(ErrorMessage = "Message Required")]
        public string Message { get; set; }
    }

    public class EmailParametersHelper
    {
        public string BodyText                      { get; set; }
        public EmailBodyViewModel EmailModelHelper  { get; set; }
    }
}

Controller.

The controller is very basic as I'm only concentrating on catching model errors and passing the message to the partial view that I'm using for the email body.

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Web.Controller.Helpers;
using Web.Model.EmailAttachmentModel;

namespace Web.Controller.Controllers
{
    public class SendEmailController : System.Web.Mvc.Controller
    {
        private readonly RenderMVCPartialsContact _renderMvcPartialsContact;

        public SendEmailController()
        {
            _renderMvcPartialsContact = new RenderMVCPartialsContact(this);
        }


        [HttpGet]
        public ActionResult Home()
        {
            return View();
        }

        [HttpPost, ValidateInput(true)]
        [ValidateAntiForgeryToken]
        public ActionResult SendEmail(EmailBodyViewModel contactModel)
        {
            if (!ModelState.IsValid)
            {
                //Not necessary, but another way to get hold of validation errors
                IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);

                List<string> errorList = new List<string>();

                var modelErrors = allErrors as ModelError[] ?? allErrors.ToArray();
                errorList.Add("<ul class=\"list-unstyled\">");
                foreach (var error in modelErrors)
                {
                    errorList.Add($"<li class=\"text-danger\">{error.ErrorMessage}</li>");
                }
                errorList.Add("</ul>");

                string displayErrors = string.Join(" ", errorList.ToArray());
                TempData["ErrorList"] = displayErrors;

                return View("Home");
            }

            EmailBodyViewModel emailBodyModel = new EmailBodyViewModel
            {
                Email   = contactModel.Email,
                Name    = contactModel.Name,
                Subject = contactModel.Subject,
                Message = contactModel.Message
            };

            //Instead of using stringbuilder to create email body, use an online source to create email body such as https://chamaileon.io/
            var emailBody = _renderMvcPartialsContact.RenderPartialViewToString("pvContactPartialViewTemplate", emailBodyModel);

            EmailParametersHelper emailModel = new EmailParametersHelper
            {
                BodyText = emailBody,
                EmailModelHelper = emailBodyModel
            };
            bool emailSentStatus = SendEmailHelper.SendEmail(emailModel);

            if (emailSentStatus)
            {
                TempData["Status"] = "Email Sent";
                return View();
            }

            TempData["Status"] = "Email Failed";
            return View();
        }
    }
}

Class for email template.

The code below simple passes the view model to the partial view that is used for the email body template.

using System.IO;
using System.Web.Mvc;
using Web.Controller.Controllers;

namespace Web.Controller.Helpers
{
    public class RenderMVCPartialsContact
    {
        private readonly SendEmailController _sendEmailController;

        public RenderMVCPartialsContact(SendEmailController sendEmailController)
        {
            _sendEmailController = sendEmailController;
        }

        public string RenderPartialViewToString(string viewName, object model)
        {
            if (string.IsNullOrEmpty(viewName))
                viewName = _sendEmailController.ControllerContext.RouteData.GetRequiredString("action");

            _sendEmailController.ViewData.Model = model;

            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult     = ViewEngines.Engines.FindPartialView(_sendEmailController.ControllerContext, viewName);
                ViewContext viewContext         = new ViewContext(_sendEmailController.ControllerContext, viewResult.View, _sendEmailController.ViewData, _sendEmailController.TempData, sw);
                viewResult.View.Render(viewContext, sw);

                return sw.GetStringBuilder().ToString();
            }
        }
    }
}
Email helper class.

C# send email with attachment.

The final bit of code is the email helper class which I use to send the email with the attachment.

This code uses HttpContext.Current.IsDebuggingEnabled to see if we are in debug mode, if yes then I send the email to the pickup directory.

using System;
using System.Net;
using System.Net.Mail;
using System.Web;
using Web.Model.EmailAttachmentModel;

namespace Web.Controller.Helpers
{
    public static class SendEmailHelper
    {
        public static bool SendEmail(EmailParametersHelper model)
        {
            var mailMessage = new MailMessage();
            mailMessage.To.Add(new MailAddress(address: model.EmailModelHelper.Email, displayName: model.EmailModelHelper.Name));
            mailMessage.From = new MailAddress(address:"YourSMTPSettings@myemail.com", displayName: "Company Name");
            mailMessage.Subject = model.EmailModelHelper.Subject;
            mailMessage.Body = model.BodyText;

            var pathToAttachment = HttpContext.Current.Server.MapPath("~/UploadedFiles/upload.zip");
            Attachment attachment = new Attachment(pathToAttachment)
            {
                Name = "Upload.zip"
            };
            mailMessage.Attachments.Add(attachment);

            mailMessage.IsBodyHtml = true;

            bool isDebuggerEnabled = HttpContext.Current.IsDebuggingEnabled;

            if (isDebuggerEnabled)
            {
                try
                {
                    using (var smtp = new SmtpClient())
                    {
                        var credential = new NetworkCredential
                        {
                            UserName = "smtpUsername",
                            Password = "smtpPassword"
                        };
                        smtp.Credentials = credential;
                        smtp.Host = "sMtpHost";
                        smtp.Port = Convert.ToInt32(90);
                        smtp.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
                        smtp.PickupDirectoryLocation = @"W:\EmailPickUp\";//Change to your own location
                        smtp.EnableSsl = false;

                        smtp.Send(mailMessage);
                        return true;

                    }
                }
                catch (SmtpFailedRecipientException e)
                {
                    throw new ApplicationException($"Failed to send email {e}");
                }
                catch (SmtpException e)
                {
                    throw new ApplicationException($"Failed to send email {e}");
                }
                catch (Exception e)
                {
                    throw new ApplicationException($"Failed to send email {e}");
                }

            }

            try
            {
                using (var smtp = new SmtpClient())
                {
                    smtp.UseDefaultCredentials = false;
                    var credential = new NetworkCredential
                    {
                        UserName = "smtpUsername",
                        Password = "smtpPassword"
                    };
                    smtp.Credentials = credential;
                    smtp.Host = "sMtpHost";
                    smtp.Port = Convert.ToInt32("sMtpPort");
                    smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
                    smtp.EnableSsl = Convert.ToBoolean("sMtpRequiresSll");


                    smtp.Send(mailMessage);
                    return true;
                }
            }
            catch (SmtpFailedRecipientException e)
            {
                throw new ApplicationException($"Failed to send email {e}");
            }
            catch (SmtpException e)
            {
                throw new ApplicationException($"Failed to send email {e}");
            }
            catch (Exception e)
            {
                throw new ApplicationException($"Failed to send email {e}");
            }
        }
    }
}
Summary.

If all goes well, you should have an email in your pickup folder with the attachment as seen below.

C# send email with attachment with working code example.

I hope you found this blog helpful and you can download the full code from GitHub if required.