目次
概要
メールに画像やドキュメントなどのファイルを添付する場合、単純なテキストメールとは異なり、MIME(Multipurpose Internet Mail Extensions)のマルチパート構造を構築する必要があります。 MailKitライブラリの BodyBuilder クラスを使用することで、複雑なMIME構造を意識することなく、本文と添付ファイルを簡潔に組み合わせて送信することができます。
仕様(入出力)
- 入力: 送信元、宛先、件名、本文、添付ファイルのパス。
- 出力: ファイルが添付された状態でのメール送信。
- 前提: .NET Standard 2.0以上。NuGetパッケージ
MailKitのインストールが必要。
基本の使い方
BodyBuilder インスタンスを作成し、TextBody に本文を、Attachments.Add にファイルパスを設定します。その後、ToMessageBody() メソッドでメッセージエンティティを生成して MimeMessage.Body に割り当てます。
var builder = new BodyBuilder();
// 本文
builder.TextBody = "添付ファイルをご確認ください。";
// ファイル添付
builder.Attachments.Add("report.pdf");
// メッセージ本体として設定
message.Body = builder.ToMessageBody();
コード全文
添付ファイルの有無を判定し、ファイルが存在する場合のみ添付して送信するクラスの実装例です。
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
class Program
{
static async Task Main()
{
var sender = new MailSender
{
From = "sender@example.com",
To = new[] { "mori01@example.com", "mori@example.com" },
Subject = "添付ファイルテスト",
Body = "画像ファイルを添付します。\nご確認ください。",
AttachmentPath = "example.png" // 添付するファイルパス
};
// テスト用ダミーファイルの作成
if (!File.Exists(sender.AttachmentPath))
{
File.WriteAllText(sender.AttachmentPath, "Dummy Image Data");
}
Console.WriteLine("送信開始...");
try
{
await sender.SendMailAsync();
Console.WriteLine("送信成功");
}
catch (Exception ex)
{
Console.WriteLine($"送信エラー: {ex.Message}");
}
}
}
public class MailSender
{
// SMTPサーバー設定
private const string SmtpHost = "smtp.example.com";
private const int SmtpPort = 587;
private const string SmtpUser = "user";
private const string SmtpPass = "password";
public IEnumerable<string> To { get; set; } = new List<string>();
public IEnumerable<string>? Cc { get; set; }
public IEnumerable<string>? Bcc { get; set; }
public string From { get; set; } = string.Empty;
public string Subject { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
public string? AttachmentPath { get; set; }
public async Task SendMailAsync()
{
var message = new MimeMessage();
// ヘッダー情報の構築
message.From.Add(new MailboxAddress(PickupName(From), From));
if (To != null)
{
foreach (var addr in To)
message.To.Add(new MailboxAddress(PickupName(addr), addr));
}
if (Cc != null)
{
foreach (var addr in Cc)
message.Cc.Add(new MailboxAddress(PickupName(addr), addr));
}
if (Bcc != null)
{
foreach (var addr in Bcc)
message.Bcc.Add(new MailboxAddress(PickupName(addr), addr));
}
message.Subject = Subject;
// 本文と添付ファイルの構築
var builder = new BodyBuilder();
builder.TextBody = Body;
if (!string.IsNullOrEmpty(AttachmentPath) && File.Exists(AttachmentPath))
{
builder.Attachments.Add(AttachmentPath);
}
message.Body = builder.ToMessageBody();
// 送信処理
using (var smtp = new SmtpClient())
{
await smtp.ConnectAsync(SmtpHost, SmtpPort, SecureSocketOptions.Auto);
await smtp.AuthenticateAsync(SmtpUser, SmtpPass);
await smtp.SendAsync(message);
await smtp.DisconnectAsync(true);
}
}
private static string PickupName(string address)
{
if (string.IsNullOrEmpty(address)) return "";
var idx = address.IndexOf('@');
return idx > 0 ? address.Substring(0, idx) : address;
}
}
カスタムポイント
- 複数ファイル添付:
AttachmentPathをList<string>型に変更し、ループ処理でbuilder.Attachments.Add()を呼び出すことで、複数のファイルを一度に送信できます。 - メモリ上データの添付: ファイルパスではなく、プログラムで生成したデータ(
byte[]やStream)を直接添付したい場合は、builder.Attachments.Add("filename.csv", byteArray)のようにファイル名とデータを渡して添付可能です。
注意点
- ファイルサイズ: メールサーバーには通常、送信可能な最大サイズ(例: 25MB)が設定されています。巨大なファイルを添付すると
SmtpProtocolException等のエラーが発生するため、送信前にファイルサイズをチェックするロジックを組み込むことが推奨されます。 - ファイルアクセス権: 指定したファイルが別のプロセスで使用中(ロックされている)の場合、読み込みエラーが発生します。
まとめ
MailKitを使用して添付ファイル付きメールを送信する際は、BodyBuilderクラスを使用するのが最も確実な方法です。このクラスはテキスト本文とバイナリデータを適切なマルチパート形式(multipart/mixed)に自動的に構成してくれるため、開発者はMIME構造の詳細を意識する必要がありません。ファイルパスを指定するだけで添付が可能ですが、実運用ではファイルの存在確認やサイズ制限への配慮が必要です。
