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
MailMessagewith sender, recipient, subject, and HTML body.Adds optional data: includes an attachment when
filePathis provided and adds a reply-to address when specified.Sends over SMTP: uses
SmtpClientwith 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 |
| SendGrid SMTP relay endpoint |
Port |
| Submission port used by the example |
Username |
| Required literal username when an API key is used for SMTP authentication |
Password | SendGrid API key | Secret credential used to authenticate |
TLS |
| 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.