MailKit для C# (.NET): полное руководство с примерами
1. Что это и зачем нужна
MailKit — это мощная, кроссплатформенная библиотека с открытым исходным кодом для работы с электронной почтой в экосистеме .NET. Она предоставляет полный набор инструментов для создания, отправки, получения и обработки email-сообщений. В отличие от устаревшей System.Net.Mail, MailKit предлагает современный API, полную поддержку MIME (Multipurpose Internet Mail Extensions), работу с S/MIME и OpenPGP, а также асинхронные операции, что критически важно для высоконагруженных приложений.
Зачем нужна MailKit? Если вы разрабатываете на C# и сталкиваетесь с необходимостью отправлять email с вложениями, парсить входящие письма, работать с разными почтовыми протоколами (SMTP, POP3, IMAP) или обрабатывать сложные форматы писем (HTML, вложения, подписи), — MailKit станет вашим незаменимым инструментом. Она используется в production-среде тысячами компаний, включая Microsoft (в некоторых внутренних сервисах), и поддерживает .NET Framework, .NET Core, .NET 5+ и даже Xamarin/MAUI.
Ключевые преимущества MailKit перед аналогами: полная поддержка последних стандартов email (RFC 2045-2049, RFC 2822, RFC 5322), встроенная поддержка SSL/TLS, работа с прокси, потоковая обработка больших вложений и высокая производительность благодаря использованию System.IO.Pipelines и async/await.
2. Установка
MailKit устанавливается через менеджер пакетов NuGet. Выполните одну из следующих команд в консоли диспетчера пакетов (Package Manager Console) или в терминале .NET CLI:
// Через .NET CLI
dotnet add package MailKit
// Через Package Manager Console
Install-Package MailKit
// Или через NuGet Package Manager в Visual Studio
// Найдите "MailKit" и установите последнюю стабильную версию
После установки в проект будет добавлена зависимость от MimeKit (базовая библиотека для работы с MIME-сообщениями) — она устанавливается автоматически как транзитивная зависимость.
3. Быстрый старт — минимальный рабочий пример
Ниже приведен минимальный пример отправки простого текстового письма через SMTP-сервер Gmail. Обратите внимание: для работы с Gmail необходимо использовать пароль приложения (App Password) или OAuth 2.0.
using MailKit.Net.Smtp;
using MimeKit;
// Создаем сообщение
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Отправитель", "sender@gmail.com"));
message.To.Add(new MailboxAddress("Получатель", "recipient@example.com"));
message.Subject = "Тестовое письмо из MailKit";
message.Body = new TextPart("plain") { Text = "Привет! Это тестовое сообщение." };
// Отправляем через SMTP
using (var client = new SmtpClient())
{
client.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls);
client.Authenticate("sender@gmail.com", "your-app-password");
client.Send(message);
client.Disconnect(true);
}
Console.WriteLine("Письмо отправлено!");
4. Основные методы/функции/классы
4.1. SmtpClient.Connect()
Сигнатура: Task ConnectAsync(string host, int port, SecureSocketOptions options, CancellationToken cancellationToken = default)
Что делает: Устанавливает соединение с SMTP-сервером. Параметр SecureSocketOptions определяет тип шифрования: None, Auto, SslOnConnect, StartTls.
using var client = new SmtpClient();
await client.ConnectAsync("smtp.mail.ru", 465, SecureSocketOptions.SslOnConnect);
4.2. SmtpClient.Authenticate()
Сигнатура: Task AuthenticateAsync(string userName, string password, CancellationToken cancellationToken = default)
Что делает: Аутентифицирует пользователя на SMTP-сервере. Поддерживает SASL-механизмы (LOGIN, PLAIN, CRAM-MD5 и др.).
await client.AuthenticateAsync("user@example.com", "password");
4.3. SmtpClient.Send()
Сигнатура: Task SendAsync(MimeMessage message, CancellationToken cancellationToken = default, ITransferProgress progress = null)
Что делает: Отправляет подготовленное MIME-сообщение. Возвращает уникальный идентификатор письма (Message-Id).
var response = await client.SendAsync(message);
Console.WriteLine($"Письмо отправлено. ID: {response}");
4.4. ImapClient.Inbox.Open()
Сигнатура: Task
Что делает: Открывает папку "Входящие" (Inbox) с указанным уровнем доступа (ReadOnly или ReadWrite).
using var imap = new ImapClient();
await imap.ConnectAsync("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
await imap.AuthenticateAsync("user@gmail.com", "password");
var inbox = imap.Inbox;
await inbox.OpenAsync(FolderAccess.ReadOnly);
Console.WriteLine($"Всего писем: {inbox.Count}");
4.5. IMailFolder.GetMessage()
Сигнатура: Task
Что делает: Загружает полное MIME-сообщение по его уникальному идентификатору (UID).
var uid = new UniqueId(12345);
var message = await inbox.GetMessageAsync(uid);
Console.WriteLine($"Тема: {message.Subject}");
4.6. MimeMessage.BodyParts
Сигнатура: Свойство IList
Что делает: Возвращает коллекцию всех частей тела письма (текст, HTML, вложения). Позволяет итерировать и обрабатывать каждую часть.
foreach (var part in message.BodyParts)
{
if (part is TextPart textPart)
Console.WriteLine($"Текст: {textPart.Text}");
if (part is MimePart mimePart && mimePart.IsAttachment)
Console.WriteLine($"Вложение: {mimePart.FileName}");
}
4.7. TextPart и Multipart
Сигнатура: TextPart(string mediaSubtype) и Multipart(string mediaSubtype)
Что делает: TextPart представляет текстовую часть письма (plain text или HTML). Multipart — контейнер для нескольких частей (например, текст + вложение).
var body = new Multipart("mixed");
body.Add(new TextPart("plain") { Text = "Текст письма" });
body.Add(new MimePart("application", "pdf")
{
Content = new MimeContent(File.OpenRead("document.pdf")),
FileName = "document.pdf"
});
message.Body = body;
4.8. MailboxAddress
Сигнатура: MailboxAddress(string name, string address)
Что делает: Создает объект, представляющий email-адрес с отображаемым именем. Используется в полях From, To, Cc, Bcc.
message.From.Add(new MailboxAddress("Иван Иванов", "ivan@example.com"));
message.To.Add(new MailboxAddress("Петр Петров", "petr@example.com"));
4.9. HeaderList
Сигнатура: Свойство HeaderList Headers { get; }
Что делает: Предоставляет доступ к заголовкам письма. Позволяет добавлять, изменять или читать кастомные заголовки.
message.Headers.Add("X-Custom-Header", "my-value");
string replyTo = message.Headers["Reply-To"];
4.10. Pop3Client.GetMessage()
Сигнатура: Task
Что делает: Загружает сообщение с POP3-сервера по его порядковому номеру (начиная с 0).
using var pop3 = new Pop3Client();
await pop3.ConnectAsync("pop.gmail.com", 995, SecureSocketOptions.SslOnConnect);
await pop3.AuthenticateAsync("user@gmail.com", "password");
var message = await pop3.GetMessageAsync(0);
Console.WriteLine($"Первое письмо: {message.Subject}");
await pop3.DisconnectAsync(true);
5. Реальный практический пример (100-200 строк кода)
Ниже представлен полноценный пример приложения, которое подключается к IMAP-серверу, сканирует папку "Входящие", находит письма с определенной темой, скачивает все вложения и отправляет отчет на указанный email.
using MailKit;
using MailKit.Net.Imap;
using MailKit.Net.Smtp;
using MailKit.Search;
using MimeKit;
class EmailProcessor
{
private const string ImapHost = "imap.example.com";
private const int ImapPort = 993;
private const string SmtpHost = "smtp.example.com";
private const int SmtpPort = 587;
private const string UserName = "user@example.com";
private const string Password = "your-password";
private const string ReportEmail = "admin@example.com";
public async Task ProcessInboxAsync()
{
// 1. Подключаемся к IMAP
using var imap = new ImapClient();
await imap.ConnectAsync(ImapHost, ImapPort, SecureSocketOptions.SslOnConnect);
await imap.AuthenticateAsync(UserName, Password);
var inbox = imap.Inbox;
await inbox.OpenAsync(FolderAccess.ReadOnly);
// 2. Ищем письма с темой "Invoice" за последние 7 дней
var query = SearchQuery.SubjectContains("Invoice")
.And(SearchQuery.DeliveredAfter(DateTime.UtcNow.AddDays(-7)));
var uids = await inbox.SearchAsync(query);
Console.WriteLine($"Найдено писем: {uids.Count}");
var attachmentsDir = Path.Combine(Directory.GetCurrentDirectory(), "attachments");
Directory.CreateDirectory(attachmentsDir);
var downloadedFiles = new List();
// 3. Обрабатываем каждое письмо
foreach (var uid in uids)
{
var message = await inbox.GetMessageAsync(uid);
Console.WriteLine($"Обработка: {message.Subject} от {message.Date}");
// Сохраняем вложения
foreach (var attachment in message.Attachments)
{
if (attachment is MimePart mimePart)
{
var fileName = mimePart.FileName ?? $"attachment_{Guid.NewGuid()}.bin";
var filePath = Path.Combine(attachmentsDir, fileName);
using var stream = File.Create(filePath);
await mimePart.Content.DecodeToAsync(stream);
downloadedFiles.Add(filePath);
Console.WriteLine($"Сохранено: {filePath}");
}
}
}
await imap.DisconnectAsync(true);
// 4. Отправляем отчет
if (downloadedFiles.Count > 0)
{
await SendReportAsync(downloadedFiles);
}
}
private async Task SendReportAsync(List files)
{
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Email Processor", UserName));
message.To.Add(new MailboxAddress("Admin", ReportEmail));
message.Subject = $"Отчет: обработано {files.Count} вложений";
var body = new TextPart("plain")
{
Text = $"Были загружены следующие файлы:\n{string.Join("\n", files)}"
};
using var client = new SmtpClient();
await client.ConnectAsync(SmtpHost, SmtpPort, SecureSocketOptions.StartTls);
await client.AuthenticateAsync(UserName, Password);
await client.SendAsync(message);
await client.DisconnectAsync(true);
Console.WriteLine("Отчет отправлен.");
}
public static async Task Main()
{
var processor = new EmailProcessor();
await processor.ProcessInboxAsync();
}
}
6. Советы по производительности и типичные ошибки
Советы по производительности
- Всегда используйте асинхронные методы (
ConnectAsync,SendAsyncи т.д.). Это особенно важно для серверных приложений, чтобы не блокировать потоки. - Повторно используйте SMTP-клиент для отправки нескольких писем. Создание нового подключения для каждого письма — дорогая операция. Используйте пул соединений или один экземпляр
SmtpClient. - Используйте потоковую обработку для больших вложений. Вместо загрузки всего вложения в память, используйте
Content.DecodeToAsync(stream)для записи напрямую в файл. - Ограничивайте количество одновременных подключений к IMAP/POP3. Большинство почтовых серверов имеют лимиты (обычно 10-20 одновременных соединений).
- Кэшируйте UniqueId писем, чтобы не сканировать всю папку каждый раз. Используйте
IMailFolder.Fetch()для выборочной загрузки только нужных полей.
Типичные ошибки
- Игнорирование SSL-сертификатов: Никогда не используйте
client.ServerCertificateValidationCallback = (
Также в библиотеке
Prometheus метрики в Swift: интеграция для iOS/macOS приложений
Генератор QR-кодов на Go (Golang) с библиотекой go-qrcode
Swagger/OpenAPI генерация для TypeScript: лучшие инструменты
GraphQL для C# (.NET): Полное руководство по библиотеке GraphQL.NET