.Net MailMessage-Objekt als EML-Datei speichern: Unterschied zwischen den Versionen

Aus maxTechCorner
Deko (Diskussion | Beiträge)
imported>TechCorner-Redaktion
Überarbeitung: MailKit/MimeKit, Fix PickupDirectoryLocation, Kategorie Softwareentwicklung, Stand Oktober 2026
 
(3 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
==='''Symptom'''===
{{Steckbrief
E-Mail-Nachrichten, die von einem Webserver erzeugt werden, können wegen eines Fehlers (z. B. Netzwerkfehler, Programmfehler, etc.) nicht verschickt werden und gehen sofort verloren. Die Fehlersuche wird dadurch erheblich erschwert.
| gilt_fuer  = .NET 8/10, .NET Framework 4.8.x; System.Net.Mail und MailKit/MimeKit 4.x
| bereich    = Softwareentwicklung
| dauer      = ca. 15 Minuten
| rechte      = Schreibrechte im Ablageordner der Anwendung
| stand      = Oktober 2026
}}
'''Ein .NET-MailMessage-Objekt als EML-Datei speichern''' sichert E-Mails, die Ihre Anwendung wegen eines Fehlers nicht versenden konnte – samt Kopfzeilen und Anhängen. Statt nur einer Fehlermeldung im Log liegt die Original-Mail vor, lässt sich in Outlook oder Thunderbird öffnen und später erneut versenden.


==='''Ursache und Lösung'''===
[[Datei:NET-MailMessage-EML.png|thumb|center|750px|Nicht versendete E-Mails als EML-Datei sichern: mit MailKit über WriteToAsync oder mit System.Net.Mail über ein Pickup-Verzeichnis mit absolutem Pfad.]]
Tritt ein Fehler beim Mailversand auf, kann der Fehler zwar mit den üblichen Logging-Mechanismen registriert werden, die Original-E-Mail aber ist verloren. Insbesondere wenn ein Netzwerkfehler vorliegt und die E-Mail daher auch nicht verdeckt (BCC) an Standardempfänger geschickt werden kann, bietet sich die Lösung an, das MailMessage-Objekt für die Fehlersuche als EML-Datei auf dem Server zu speichern. EML-Dateien enthalten den gesamten Inhalt einer E-Mail und deren Kopfdaten, also z. B. auch Informationen über Absender und Empfänger. EML-Dateien können mit E-Mail-Programmen wie MS Outlook oder Mozilla Thunderbird direkt geöffnet werden. Mithilfe der statischen Erweiterungsklasse „MailMessageExtensions“ kann ein MailMessage-Objekt direkt als EML-Datei gespeichert werden.<br />


<pre>using System;
== Problem ==
using System.Collections.Generic;
* Von einem Webserver oder Dienst erzeugte E-Mails scheitern beim Versand (SMTP-Server nicht erreichbar, Authentifizierung, Zeitüberschreitung).
using System.IO;
* Im Log steht nur die Exception – die eigentliche Mail ist verloren und der Fehler schwer nachzuvollziehen.
using System.Linq;
 
using System.Net.Mail;
== Lösung ==
using System.Text;
=== Variante 1: MailKit/MimeKit (empfohlen) ===
Microsoft empfiehlt <code>System.Net.Mail.SmtpClient</code> nicht mehr für neue Entwicklungen, weil er moderne Protokolle und Anmeldeverfahren (z. B. OAuth 2.0) nicht unterstützt. Der Standard ist '''MailKit''' mit dem Nachrichtenmodell '''MimeKit'''. Dort ist das Speichern als EML ein Einzeiler:
<syntaxhighlight lang="bash">
dotnet add package MailKit
</syntaxhighlight>
<syntaxhighlight lang="csharp">
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
 
var message = new MimeMessage();
message.From.Add(MailboxAddress.Parse("shop@example.com"));
message.To.Add(MailboxAddress.Parse("kunde@example.com"));
message.Subject = "Ihre Bestellung";
message.Body = new TextPart("plain") { Text = "Vielen Dank für Ihre Bestellung." };


namespace MaxIt.TechCorner
try
{
    using var smtp = new SmtpClient();
    await smtp.ConnectAsync("smtp.example.com", 587, SecureSocketOptions.StartTls);
    await smtp.AuthenticateAsync("benutzer", "passwort");
    await smtp.SendAsync(message);
    await smtp.DisconnectAsync(true);
}
catch (Exception ex)
{
{
public static class MailMessageExtensions
    var dir = Path.Combine(AppContext.BaseDirectory, "mail-fehler");
{
    Directory.CreateDirectory(dir);
 
    var file = Path.Combine(dir, $"{DateTime.UtcNow:yyyyMMdd-HHmmss}-{Guid.NewGuid():N}.eml");
/// <summary>
    await message.WriteToAsync(file);         // komplette Mail als EML sichern
/// Stores a MailMessage as EML file.
    logger.LogError(ex, "Mailversand fehlgeschlagen, gesichert unter {File}", file);
/// </summary>
/// <param name="message">The MailMessage object to be stored.</param>
public static void Archive(this MailMessage message)
{
using (SmtpClient diskclient = new SmtpClient("mysmtphost"))
{
diskclient.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
diskclient.PickupDirectoryLocation = "%TEMP%\\mails";
diskclient.Send(message);
}
}
}
}
}
</pre>
</syntaxhighlight>
Dazu wird ein neues SmtpClient-Objekt erzeugt, dessen Option „DeliveryMethod“ den Wert „SmtpDe-liveryMethod.SpecifiedPickupDirectory“ erhält.<br />
Eine gesicherte Mail lässt sich später mit <code>MimeMessage.Load(file)</code> wieder einlesen und erneut versenden.
Dadurch wird beim Versand das MailMessage-Objekt als EML-Datei gespeichert. Der Speicherort wird der Eigenschaft „PickupDirectoryLocation“ zugewiesen.<br />
Verwendet wird die Erweiterung, indem deren Namespace eingebunden und im Code die Archive()-Methode für das MailMessage-Objekt aufgerufen wird:<br />
<pre>System.Net.Mail.SmtpClient smtpclient;
System.Net.Mail.MailMessage message;


// ...
=== Variante 2: System.Net.Mail (Bestandscode) ===
Für bestehende Anwendungen mit <code>MailMessage</code> funktioniert der Trick über das Pickup-Verzeichnis: Ein zweiter <code>SmtpClient</code> „versendet“ die Mail als Datei in einen Ordner.
<syntaxhighlight lang="csharp">
using System.Net.Mail;


public static class MailMessageExtensions
{
    /// <summary>Speichert eine MailMessage als EML-Datei im angegebenen Ordner.</summary>
    public static void Archive(this MailMessage message, string directory)
    {
        Directory.CreateDirectory(directory);
        using var diskClient = new SmtpClient
        {
            DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory,
            PickupDirectoryLocation = directory
        };
        diskClient.Send(message);
    }
}
</syntaxhighlight>
Verwendung im Fehlerfall:
<syntaxhighlight lang="csharp">
try
try
{
{
// Try to send message
    smtpClient.Send(message);
smtpclient.Send(message);
}
}
catch (Exception ex)
catch (SmtpException ex)
{
{
// Archive message
    message.Archive(Path.Combine(Path.GetTempPath(), "mail-fehler"));
message.Archive();
    logger.LogError(ex, "Mailversand fehlgeschlagen");
}
}
</pre>
</syntaxhighlight>
Zusätzlich zu fehlerbeschreibenden Logging-Nachrichten steht so auch die E-Mail selbst, inklusive eventuell vorhandener Dateianhänge, für die Fehlersuche zur Verfügung.


==='''Weitere Informationen'''===
{{Warnung|<code>PickupDirectoryLocation</code> erwartet einen '''absoluten Pfad''' zu einem '''existierenden''' Ordner. Umgebungsvariablen wie <code>%TEMP%</code> werden nicht aufgelöst – deshalb <code>Path.GetTempPath()</code> bzw. <code>Directory.CreateDirectory</code> verwenden. Der Dateiname wird automatisch als GUID vergeben.}}
Mehr Informationen zur Anwender- und Netzwerkbetreuung finden Sie auf<br />
[https://www.max-it.de/managed-services/managed-client-services/ www.max-it.de/managed-services/managed-client-services]


=== '''Kontakt''' ===
== Hinweise ==
Wenn Sie Fragen oder Anmerkungen zu diesem Artikel haben, melden Sie sich bitte bei uns:<br />
* '''Datenschutz:''' EML-Dateien enthalten personenbezogene Daten. Ablageordner nur für das Dienstkonto lesbar machen, nicht unter <code>wwwroot</code> ablegen und alte Dateien automatisch löschen ([[DSGVO]]).
[http://mailto:techcorner@max-it.de techcorner@max-it.de].<br />
* '''Wiederholung:''' Für produktive Systeme eignet sich ein Hintergrunddienst, der den Ordner regelmäßig abarbeitet und gesicherte Mails erneut versendet.
* '''Microsoft 365:''' Der SMTP-Versand mit Basic Authentication wird bei Exchange Online abgeschaltet. MailKit unterstützt OAuth 2.0 bzw. den Versand über Microsoft Graph.
* Bei Entwicklung und Modernisierung von .NET-Anwendungen unterstützt Sie die [https://www.max-it.de/development/individuelle-softwareentwicklung/ individuelle Softwareentwicklung von m.a.x. it].


Über m.a.x. Informationstechnologie AG: <br />
== Siehe auch ==
Als etabliertes Münchner Systemhaus zeichnen wir uns seit 1989 als verlässlicher IT-Partner mittelständischer und<br />
* [[SMTP]]
großer Unternehmen aus. Unser Portfolio reicht von IT- Services über individuelle Softwareentwicklung bis hin zur ERP-Beratung.<br />
* [[WCF Rest-Service]]
* [[DSGVO]]


=== '''Tags''' ===
== Links und Quellen ==
.Net, SmtpClient, MailMessage, archive, EML, store to disk
* [https://learn.microsoft.com/de-de/dotnet/api/system.net.mail.smtpclient Microsoft Learn: SmtpClient-Klasse (mit Empfehlung für MailKit)]
* [https://www.max-it.de/development/individuelle-softwareentwicklung/ Individuelle Softwareentwicklung von m.a.x. it]


{{Uebermax}}
[[Kategorie:Softwareentwicklung]]


[[Kategorie: Server-Software]]

Aktuelle Version vom 14. Oktober 2026, 00:00 Uhr

Auf einen Blick

Gilt für.NET 8/10, .NET Framework 4.8.x; System.Net.Mail und MailKit/MimeKit 4.x
BereichSoftwareentwicklung
Dauerca. 15 Minuten
RechteSchreibrechte im Ablageordner der Anwendung
StandOktober 2026

Ein .NET-MailMessage-Objekt als EML-Datei speichern sichert E-Mails, die Ihre Anwendung wegen eines Fehlers nicht versenden konnte – samt Kopfzeilen und Anhängen. Statt nur einer Fehlermeldung im Log liegt die Original-Mail vor, lässt sich in Outlook oder Thunderbird öffnen und später erneut versenden.

Nicht versendete E-Mails als EML-Datei sichern: mit MailKit über WriteToAsync oder mit System.Net.Mail über ein Pickup-Verzeichnis mit absolutem Pfad.

Problem

  • Von einem Webserver oder Dienst erzeugte E-Mails scheitern beim Versand (SMTP-Server nicht erreichbar, Authentifizierung, Zeitüberschreitung).
  • Im Log steht nur die Exception – die eigentliche Mail ist verloren und der Fehler schwer nachzuvollziehen.

Lösung

Variante 1: MailKit/MimeKit (empfohlen)

Microsoft empfiehlt System.Net.Mail.SmtpClient nicht mehr für neue Entwicklungen, weil er moderne Protokolle und Anmeldeverfahren (z. B. OAuth 2.0) nicht unterstützt. Der Standard ist MailKit mit dem Nachrichtenmodell MimeKit. Dort ist das Speichern als EML ein Einzeiler:

dotnet add package MailKit
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;

var message = new MimeMessage();
message.From.Add(MailboxAddress.Parse("shop@example.com"));
message.To.Add(MailboxAddress.Parse("kunde@example.com"));
message.Subject = "Ihre Bestellung";
message.Body = new TextPart("plain") { Text = "Vielen Dank für Ihre Bestellung." };

try
{
    using var smtp = new SmtpClient();
    await smtp.ConnectAsync("smtp.example.com", 587, SecureSocketOptions.StartTls);
    await smtp.AuthenticateAsync("benutzer", "passwort");
    await smtp.SendAsync(message);
    await smtp.DisconnectAsync(true);
}
catch (Exception ex)
{
    var dir = Path.Combine(AppContext.BaseDirectory, "mail-fehler");
    Directory.CreateDirectory(dir);
    var file = Path.Combine(dir, $"{DateTime.UtcNow:yyyyMMdd-HHmmss}-{Guid.NewGuid():N}.eml");
    await message.WriteToAsync(file);          // komplette Mail als EML sichern
    logger.LogError(ex, "Mailversand fehlgeschlagen, gesichert unter {File}", file);
}

Eine gesicherte Mail lässt sich später mit MimeMessage.Load(file) wieder einlesen und erneut versenden.

Variante 2: System.Net.Mail (Bestandscode)

Für bestehende Anwendungen mit MailMessage funktioniert der Trick über das Pickup-Verzeichnis: Ein zweiter SmtpClient „versendet“ die Mail als Datei in einen Ordner.

using System.Net.Mail;

public static class MailMessageExtensions
{
    /// <summary>Speichert eine MailMessage als EML-Datei im angegebenen Ordner.</summary>
    public static void Archive(this MailMessage message, string directory)
    {
        Directory.CreateDirectory(directory);
        using var diskClient = new SmtpClient
        {
            DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory,
            PickupDirectoryLocation = directory
        };
        diskClient.Send(message);
    }
}

Verwendung im Fehlerfall:

try
{
    smtpClient.Send(message);
}
catch (SmtpException ex)
{
    message.Archive(Path.Combine(Path.GetTempPath(), "mail-fehler"));
    logger.LogError(ex, "Mailversand fehlgeschlagen");
}


WarnungPickupDirectoryLocation erwartet einen absoluten Pfad zu einem existierenden Ordner. Umgebungsvariablen wie %TEMP% werden nicht aufgelöst – deshalb Path.GetTempPath() bzw. Directory.CreateDirectory verwenden. Der Dateiname wird automatisch als GUID vergeben.

Hinweise

  • Datenschutz: EML-Dateien enthalten personenbezogene Daten. Ablageordner nur für das Dienstkonto lesbar machen, nicht unter wwwroot ablegen und alte Dateien automatisch löschen (DSGVO).
  • Wiederholung: Für produktive Systeme eignet sich ein Hintergrunddienst, der den Ordner regelmäßig abarbeitet und gesicherte Mails erneut versendet.
  • Microsoft 365: Der SMTP-Versand mit Basic Authentication wird bei Exchange Online abgeschaltet. MailKit unterstützt OAuth 2.0 bzw. den Versand über Microsoft Graph.
  • Bei Entwicklung und Modernisierung von .NET-Anwendungen unterstützt Sie die individuelle Softwareentwicklung von m.a.x. it.

Siehe auch

Links und Quellen


Über m.a.x. it Die m.a.x. Informationstechnologie AG ist seit über 30 Jahren IT-Partner mittelständischer und großer Unternehmen in München und bietet maßgeschneiderte Lösungen und Services in den Bereichen Cloud, Cybersecurity, Netzwerk, Windows, Linux und Softwareentwicklung. Sie haben eine Frage zu diesem Artikel oder brauchen Unterstützung? Kontakt aufnehmen