What This Tutorial Covers

SendGrid supports multiple ways to send email. This tutorial focuses specifically on SMTP relay, not the SendGrid Web API. It is aimed at existing .NET Framework 4.8 applications that already use System.Net.Mail.

Microsoft does not recommend SmtpClient for new development. The implementation is preserved here because it is useful for maintained .NET Framework 4.8 applications where this approach is already tested.

Create an EmailService for SendGrid SMTP

The EmailService class encapsulates the SMTP configuration and email-sending logic. Its Send method builds a MailMessage, optionally adds an attachment and reply-to address, and sends the message through SendGrid's SMTP relay.

public class EmailService
{
	private static readonly ILogger log = Logger.Create(typeof(EmailService));

	private readonly string _appEmailSmtpHost;
	private readonly int _appEmailSmtpPort;
	private readonly string _appEmailNetworkCredentialUserName;
	private readonly string _appEmailNetworkCredentialPassword;
	private readonly string _fromEmailAddress;
	private readonly string _fromDisplayName;

	private SmtpClient _smtpClient = null;

	public EmailService(string appEmailSmtpHost,
		int appEmailSmtpPort,
		string appEmailNetworkCredentialUserName,
		string appEmailNetworkCredentialPassword,
		string fromEmailAddress,
		string fromDisplayName)
	{
		_appEmailSmtpHost = appEmailSmtpHost;
		_appEmailSmtpPort = appEmailSmtpPort;
		_appEmailNetworkCredentialPassword = appEmailNetworkCredentialPassword;
		_appEmailNetworkCredentialUserName = appEmailNetworkCredentialUserName;
		_fromEmailAddress = fromEmailAddress;
		_fromDisplayName = fromDisplayName;
	}

	protected SmtpClient SmtpClient
	{
		get
		{
			return _smtpClient ?? (_smtpClient = new SmtpClient(_appEmailSmtpHost, _appEmailSmtpPort)
			{
				EnableSsl = true,
				DeliveryMethod = SmtpDeliveryMethod.Network,
				UseDefaultCredentials = false,
				Credentials = new NetworkCredential(_appEmailNetworkCredentialUserName, _appEmailNetworkCredentialPassword),
				Timeout = 3 * 60 * 1000 // 180 seconds
			});
		}
	}

	public bool Send(string to, string subject, string bodyHtml, string filePath, string replyTo = null)
	{
		using (var mailMessage = new MailMessage())
		{
			try
			{
				mailMessage.IsBodyHtml = true;
				mailMessage.From = new MailAddress(_fromEmailAddress, _fromDisplayName);
				mailMessage.To.Add(to);
				mailMessage.Subject = subject;
				mailMessage.Body = $"<html><body>{bodyHtml}</body></html>";
				mailMessage.IsBodyHtml = true;

				if (!string.IsNullOrWhiteSpace(filePath))
					mailMessage.Attachments.Add(new Attachment(filePath));

				if (!string.IsNullOrWhiteSpace(replyTo))
				{
					mailMessage.ReplyToList.Add(new MailAddress(replyTo));
					mailMessage.Headers.Add("Reply-To", replyTo);
				}
				
				SmtpClient.Send(mailMessage);
			}
			catch (SmtpException smtpEx)
			{
				log.Error("SMTP Error sending notification", smtpEx);

				return false;
			}
			catch (Exception ex)
			{
				log.Error("Error sending notification", ex);

				return false;
			}
		}

		return true;
	}
}

What the Send method does

  • Builds the message: creates a MailMessage with sender, recipient, subject, and HTML body.

  • Adds optional data: includes an attachment when filePath is provided and adds a reply-to address when specified.

  • Sends over SMTP: uses SmtpClient with the configured SendGrid host, port, credentials, and TLS.

  • Handles failures: catches SMTP-specific and general exceptions, logs the error, and returns a boolean result.

Test the Send Method in Program.cs

Once the service is configured, test it with a verified sender, recipient, subject, and HTML body. The following code is a tested console application example.

Keep the API key out of source control

The placeholder in the example is intentional. In a real application, load the SendGrid API key from a secure configuration source rather than committing it to the repository.

internal class Program
{
	static void Main(string[] args)
	{
		string smtpHost = "smtp.sendgrid.net";
		int smtpPort = 587;
		
		string smtpUser = "apikey"; //this is fixed value, leave it
		string smtpPassword = "YOUR_SENDGRID_API_KEY"; // such as SG.aDc0s3U3RtG1cNOTDWJnxA.MBswEuYGa...
		
		string fromEmail = "verified@yourdomain.com"; // Must be verified in SendGrid
		string fromDisplayName = "Your Company";

		var emailService = new EmailService(smtpHost, smtpPort, smtpUser, smtpPassword, fromEmail, fromDisplayName);

		// Test email sending
		string to = "recipient@example.com";
		string subject = "Test Email from Console App";
		string bodyHtml = "<p>Please ignore this message.</p>";
		string replyTo = "john.rambo.12347@gmail.com";
		
		bool result = emailService.Send(to, subject, bodyHtml, null, replyTo);
		
		Console.ForegroundColor = result ? ConsoleColor.Green : ConsoleColor.Red;
		Console.WriteLine(result ? "Email sent successfully." : "Failed to send email.");
		Console.ResetColor();
		Console.ReadKey();
	}
}

SendGrid SMTP Configuration Details

The example uses SendGrid's SMTP relay at smtp.sendgrid.net on port 587. When authenticating with a SendGrid API key, the SMTP username is the literal value apikey, while the API key itself is used as the password.

SendGrid settings used by the tested example

Setting

Value

Purpose

SMTP host

smtp.sendgrid.net

SendGrid SMTP relay endpoint

Port

587

Submission port used by the example

Username

apikey

Required literal username when an API key is used for SMTP authentication

Password

SendGrid API key

Secret credential used to authenticate

TLS

EnableSsl = true

Enables encrypted SMTP transport in the tested implementation

Verify the SendGrid Sender Identity

Before SendGrid accepts mail from the address used in From, the sender must be authorized in your SendGrid account. Depending on the account configuration, this can be handled through a verified sender identity or an authenticated domain.

If the sender is not authorized, SendGrid rejects the message. A typical failure looks like this:

The from address does not match a verified Sender Identity. Mail cannot be sent until this error is resolved. Visit https://sendgrid.com/docs/for-developers/sending-email/sender-identity/ to see the Sender Identity requirements)
   in System.Net.Mail.DataStopCommand.CheckResponse(SmtpStatusCode statusCode, String serverResponse)
   in System.Net.Mail.DataStopCommand.Send(SmtpConnection conn)
   in System.Net.Mail.SmtpConnection.OnClose(Object sender, EventArgs args)
   in System.Net.ClosableStream.Close()
   in System.Net.Mail.MailWriter.Close()
   in System.Net.Mail.SmtpClient.Send(MailMessage message)

Troubleshooting order

Check the sender identity first, then the SMTP host and port, the literal apikey username, the API key, and finally network or firewall restrictions.

When to Use This Approach

This implementation is a pragmatic fit for an existing .NET Framework 4.8 codebase that already relies on System.Net.Mail and needs to be sent via SendGrid SMTP.

For new .NET applications, do not treat this tutorial as a recommendation to start with SmtpClient. Microsoft explicitly does not recommend it for new development. In maintained legacy applications, however, isolating SMTP logic in a small service can keep the integration understandable and contained.

Production checklist

  • Keep the SendGrid API key outside source control.

  • Authorize the sender address or domain in SendGrid.

  • Test successful delivery and failure paths.

  • Confirm attachments and reply-to behavior when your application uses them.

  • Log SMTP failures without exposing credentials or message secrets.