C# Send Email: A Deep Dive with Tim Corey
Welcome to a comprehensive look at sending emails in a C# Windows Forms application using the insights from Tim Corey’s “C# App Start To Finish – Lesson 26.” In this lesson, Tim demonstrates how to build functionality that emails users, particularly in the context of a tournament tracker application.
Transactional emails—automated, personalized messages triggered by user actions—are essential for modern web applications. C# web applications often rely on transactional email APIs, such as Mailgun and SendGrid, for reliable and scalable delivery of production-ready emails.
This article will guide you through the process Tim demonstrates, including deciding where to place the email code, creating helper methods, building dynamic emails, and sending them using the built-in C# libraries. Visual Studio is the primary IDE for developing and testing email functionality in C# applications.
Email delivery platforms like Mailtrap can be used to monitor deliverability and test email sending during development.
Introduction
Tim begins by reminding us of the core requirement: only one round of a tournament can be played at a time. This means that once a round is completed, teams need to be notified about their next match. These notification emails are a type of transactional email, typically sent automatically in response to user actions in web applications. Email is a practical solution to ensure participants are informed promptly, and Tim walks through building this functionality step by step.
Using a dedicated email service, such as Amazon SES, can help ensure reliable and scalable delivery of these transactional emails.
Deciding Where to Place Email Logic
Tim starts by addressing a crucial question: Where should the email logic go? He explains that it should be placed where the application is already performing key tournament logic. In this case, the best place is inside the UpdateTournamentResults method.
Why here? Because this method handles:
Determining winners of matchups
Advancing teams to the next round
- Updating database or file storage
By placing the email logic here, we only send emails after a round is completed, avoiding spamming users unnecessarily.
Tim introduces a strategy of tracking the current round before and after updating results:
If the round number changes, we know a new round has begun.
- This triggers the email notifications to users about upcoming matchups.
Checking the Current Round
To determine if a round has changed, Tim creates an extension method called CheckCurrentRound. This method iterates through all rounds in the tournament model and checks if every matchup in a round has a winner.
If all matchups are complete, it increments an output variable.
If a round is incomplete, it stops checking further rounds.
- This method returns the current round number after evaluating the tournament state.
Tim emphasizes that starting the output at 1 handles cases where no rounds are complete yet. By using this method, the application can dynamically detect when a new round starts and trigger emails.
Extracting Email Logic into a Separate Class
Tim advocates creating a dedicated EmailLogic class. This approach:
Keeps email-related code separate from tournament logic
Makes it reusable across the application
- Helps in future expansions, such as sending payment reminders or tournament summaries
Using a dedicated email client library, such as MailKit, is recommended for modern C# applications, as it provides robust features and better support compared to the outdated SmtpClient class.
He sets up a public static method called SendEmail with parameters:
From (sender email)
To (recipient emails)
Subject
- Body
The BodyBuilder class from MailKit can be used to construct HTML emails and add attachments efficiently, making it easier to send emails with files such as PDFs.
Tim suggests keeping it simple for the first version, with CC and BCC added later if needed.
Preparing the Current Round for Notifications
Once the current round is determined, Tim extracts a list of matchups for that round using LINQ. Each matchup contains entries for two competing teams.
For each matchup, he loops through:
Each team entry
- Each team member
This ensures every individual receives an email about their upcoming matchup. When sending emails to multiple recipients, the InternetAddressList class and the AddRange method can be used to efficiently add all recipient email addresses at once. It is also important to verify each recipient email address to ensure successful delivery.
Tim emphasizes the importance of gathering all necessary information, such as:
The participant’s name and email
Their team name
- The opponent’s team name
Generating Dynamic Email Content
Tim then focuses on building the email subject and body dynamically:
Subject: Simple and direct, e.g., “You have a new matchup with Team Rolling Thunder.” The subject is typically set using a string subject variable in the code, which is then assigned to the email message.
- Body: Tim uses a StringBuilder to efficiently concatenate multiple lines of text. He explains that repeatedly adding strings in C# is inefficient, as each addition creates new memory allocations.
When generating the email content, Tim considers whether to send a plain text email or an HTML email. Plain text emails are simple, compatible with all email clients, and often used for internal notifications or transactional messaging. HTML emails, on the other hand, allow for richer formatting. Sending both HTML and plain text versions can improve deliverability and ensure compatibility with various email service providers. You can send HTML emails in C# by setting the IsBodyHtml property of the MailMessage class to true, or by using the MailKit library and modifying the message body to include HTML content.
Using StringBuilder allows the application to:
Handle multiple lines for a personalized message
Include details such as the opponent’s team and round information
- Avoid performance issues even when sending hundreds of emails
Tim also handles special cases, like a bye week, where a team doesn’t have an opponent.
Validating Email Addresses
Before sending, Tim checks that the participant has a valid email address. He notes:
Even a simple check for an empty string prevents errors
Comprehensive validation (like regex) is possible but can be expensive for large datasets
- For most applications, verifying the presence of an email is sufficient
This step ensures that only participants who provided emails receive notifications.
Configuring the Sender Address
Tim explains that the sender email should be stored in App.config for flexibility. He adds:
senderEmail for the actual email address
- senderDisplayName for the sender’s name
Many email services, such as Amazon SES, require domain verification to ensure proper deliverability and avoid spam filters. This process involves adding and verifying your domain before you can reliably send emails through their API.
Later, a GlobalConfig helper retrieves these values. This abstraction allows the sender information to be changed without modifying the email logic code.
Setting Up MailMessage
To send emails, Tim uses the System.Net.Mail namespace, which is built into C#. Steps include:
Create a new MailAddress for the sender, including the display name. When configuring a new mailaddress, ensure correct account settings and authentication for programmatic email sending.
- Instantiate a MailMessage object
Add recipient email addresses
- Set subject and body
The MailMessage class allows you to add attachments using the Attachments property. You can send HTML emails in C# by setting the IsBodyHtml property of the MailMessage class to true.
Using SMTP Client
Finally, Tim sets up the SMTP client to send the email:
Configure host, port, credentials, and enable SSL if needed. While you can use your own smtp server, using a cloud-based email service like Amazon Simple Email Service (SES) is often more reliable and scalable.
Call Send(mail) to transmit the message
- This handles sending emails through standard SMTP servers like Gmail, Outlook, or a custom server, or through an email service such as Amazon SES, Mailgun, or Mailtrap.
Amazon SES (Simple Email Service) is a cost-effective and scalable email service offered by AWS to send transactional emails quickly. To integrate Amazon SES into your C# application, you need to install the AWS SES Package, and you may need to use an authentication token for secure access. Secure app access is important when configuring SMTP settings, especially when using services like Gmail or Office365, to ensure proper authentication and security.
He notes that email servers often enforce restrictions on the “From” address for security, and testing with a dummy or sandbox server is recommended.
Summary of the Email Flow
To recap Tim’s process:
Detect the current tournament round before updating results
Update tournament results and detect if the round has advanced
Extract matchups for the new round
Loop through all participants and team members
Generate dynamic email subjects and bodies
Validate email addresses
Retrieve sender information from App.config via GlobalConfig
- Send emails using MailMessage and SmtpClient
For sending transactional emails at scale, it's recommended to use transactional email APIs such as SendGrid or Mailgun. Many services offer a free plan for initial testing—SendGrid, for example, allows you to send 100 emails per day and provides analytics for email performance. Always use environment variables or secure vaults like Azure Key Vault or AWS Secrets Manager to store sensitive credentials in your C# applications. During development, you can use dotnet run to start your application and test email sending functionality.
Tim emphasizes abstraction and modularity: by isolating email logic, the application becomes easier to maintain, test, and expand.
Final Thoughts
Tim Corey’s lesson demonstrates that sending emails in a C# application is more than just calling SmtpClient.Send(). It requires careful consideration of when to send emails, gathering relevant information, validating recipients, and structuring code for maintainability. The .NET framework provides robust support for email sending via the Simple Mail Transfer Protocol (SMTP), which is the most common way of sending emails from a C# application.
By following Tim’s approach, developers can build robust, reusable email functionality that can scale with their applications, whether it’s a tournament tracker, notification system, or other user-based services. Using modern libraries and protocols like SMTP ensures reliable and maintainable email functionality in C# applications.

