Versenden von E-Mails mit DKIM mit .NET und MailKit

Versenden von E-Mails mit DKIM mit .NET und MailKit

Wer heute automatisierte E-Mails versenden will, die nicht unbedingt in jedem Spam-Filter hängen bleiben sollen, der kommt kaum an DKIM vorbei.

DKIM - DomainKeys Identified Mail - ist ein Mechanismus zur Validierung von E-Mail-Absendern; primär über DNS Einträge.

Mit Hilfe eine DNS-TXT Eintrags wird vereinfacht gesagt ein Public-Key bekannt gegeben, den der E-Mail-Empfänger verwenden kann, um den Ursprung einer E-Mail validieren zu können - wozu die E-Mail Nachricht mit Hilfe eines Private Keys eine Signatur erhält.

Mehr über die prinzipelle Funktionsweise auf Wikipedia .

Generierung der Keys

Für DKIM können selbst erstellte Schlüsselpaare verwendet werden; dazu ist kein gekauftes Zertifikat notwendig.

Dank des OpenSSL-Tools ist dies mit zwei einfachen Befehlen umsetzbar:

Erstellung des privaten Schlüssels für das Signieren der E-Mail:

1openssl genrsa -out beispiel.dkim.private 1024

Mit Hilfe des privaten Schlüssels kann nun ein öffentlicher Schlüssel erzeugt werden, der im DNS bekannt gegeben wird:

1openssl rsa -in beispiel.dkim.private -out beispiel.dkim.public -pubout -outform PEM

Setzen des DNS Eintrags

Mit Hilfe des DNS-Eintrags validiert der E-Mail Empfänger die Signatur.

Der Inhalte des öffentlichen Schlüssels - ohne den Header, Footer oder Leerzeichen - kommt nun in folgendes DNS-Format:

v=DKIM1;k=rsa;t=y;p=Undzwn/n2ndsk……UZnbhudnz=;

Der Inhalt de p-Parameters muss der Inhalt aus dem öffentlichen Schlüssel entsprechen.

Der Name des TXT-Eintrags lautet beispielselektor2021._domainkey wobei beispielselektor2021 ein Platzhalter ist, denn einer Domain können prinzipiell viele Domain Keys hinterlegt werden, sodass man jeden E-Mail Ausgang mit eigenen Schlüsseln konfigurieren kann. Der Selektor wird dabei beim Erstellen der Signatur mit in die E-Mail gepackt, sodass der E-Mail Empfänger weiß, welcher der zugehörige Eintrag ist.

Da jeder Domain-Anbieter eine andere Oberfläche mit sich bringt, wie ein TXT-Eintrag zu setzen ist, überspringe ich diesen Part.

Signieren der E-Mail mit MimeKit

Anders als mit .NET Boardmitteln, die keine direkte Möglichkeit bieten E-Mails mit DKIM zu signrieren, bietet das MimeKit entsprechende Unterstützung an.

Hierzu erzeugen wir mit der Partnerbibliothek MimeKit entsprechend eine E-Mail, setzen Absender und Empfänger sowie den Inhalt - und signieren am Schluss die E-Mail.

 1MimeMessage emailMessage = new(.....);
 2{
 3    // set from
 4    // set to
 5    // set body
 6    // set attachments
 7}
 8string pk = $"-----BEGIN RSA PRIVATE KEY-----\r\n{PrivateKeyString}\r\n-----END RSA PRIVATE KEY-----";
 9MemoryStream stream = new(Encoding.UTF8.GetBytes(pk));
10{
11    stream.Position = 0;
12}
13
14// Erzeugung des Signers mit dem privaten Schlüssel; auch das Lesen einer Datei selbst ist als Übergabeparameter möglich!
15DkimSigner dkimSigner = new DkimSigner(stream, "meinedomain.de", "beispielselektor2021");
16
17// Welche Elemente der Mail sollen mit signiert werden?
18HeaderId[] dkimSignHeaders = { HeaderId.From, HeaderId.To, HeaderId.Subject, HeaderId.Date, HeaderId.MessageId };
19
20// Signieren der Mails
21emailMessage.Body.Prepare(EncodingConstraint.SevenBit);
22dkimSigner.Sign(FormatOptions.Default, emailMessage, dkimSignHeaders);
23
24// Versenden
25smtpClient.SendAsync(emailMessage....);

Das Signieren muss unbedingt am Schluss passieren, da ansonsten entsprechend sich die Inhalte nach der Signatur verändern und die Signatur ungültig wird. Ebenso ist notwendig, dass der Inhalte der Mail - also der Body - durch Prepare() das entsprechende Encoding erhält; fehlt das, ist auch hier die Signatur am Ende ungültig.

Testen und Validieren der Signatur

Es gibt viele verschiedene Tools, die eine DKIM-Validierung anbieten; wirklich empfehlen kann ich aber im Endeffekt nur zwei Tools:

  • Microsoft Outlook kann mit Hilfe des MHA-Addins entsprechende Informationen zu E-Mail Headern anzeigen.
  • Mit Hilfe des Services https://dkimvalidator.com/ kann eine Test-E-Mail versendet werden, die entsprechend analyisiert wird

Outlook MHA:

Der Message Header Inilizer sollte - bei einer korrekten Implementierung von DKIM - folgenden Header-Ausschnitt anzeigen

1DKIM-Signature: v=1; a=rsa-sha256; d=meinedomain.de; s=1und1; c=simple/simple;
2	t=1610929057; h=from:to:subject:date:message-id;
3	bh=IR0r/61rl3Xcv7EAYlNJVNAgqOpheEklTFjbFnFyGIU=;
4	b=OXRyC6ZwDAWTVhKzmHiI0gURspIbw5xNCyzYo5D45iqcy1F5l9UljlGMU38lt4Sy3JLlAn5k2PX
5	/DIFDnmRDaBnw+hVHdlwDBC9FWJawZyyVaYzyIpQ3AG+52g8LuQ+SCqIHogFW/IkYnsNajOSVhbRZ
6	G/qQ2wnZoM0tWpDu2RA=
71705

Dies bestägtigt, dass Signatur über das MimeKit erfolgt ist.

Ein weitrer Header-Eintrag bestätigt darüber hinaus, ob die Signatur selbst gültig ist. Dies ist der Authentication-Results Header, in dem allgemeine Validierungen erfolgen; darunter auch entsprechend der DKIM-Eintrag dkim=test (signature was verified) was uns die Information gibt, dass die Validierung erfolgt und gültig ist.

1Authentication-Results: spf=pass (sender IP is xxx)
2 smtp.mailfrom=meinedomain.de; meinedomain.com; dkim=test (signature was
3 verified) header.d=meinedomain.de;zieldomain.com; dmarc=pass action=none
4 header.from=meinedomain.de;compauth=pass reason=100

Fehlersuche

Sollte die die Validierung nicht erfolgreich sein, so ist eine Validierung gar nicht so einfach.

Zunächst muss natürlich nachgeschaut werden, ob der entsprechende Header teil der E-Mail ist; wenn nicht, dann liegt der Fehler auf der Code-Seite. Ansonsten, sollte die Validierung vorhanden aber ungültig sein, liegt es meist am Key-Pair.

Lohnt sich DKIM?

Ganz klar: Ja.

DKIM ist relevant für das Spam-Scoring; und entsprechend sollten automatisierte E-Mails - zB. von Plattformen und Webseiten - ein entsprechend hohes Scoring haben, sodass eben solche Mails nicht im Spam-Filter landen und die Kommunikation mit dem Anwender erschweren.

Dank dem MimeKit und dem MailKit ist das - zumindest aus .NET sicht für SMTP - jedoch kein Problem mehr.


Comments

Twitter Facebook LinkedIn WhatsApp