Die meisten kostenlosen Mail-Server lassen nur E-Mails an eine begrenzte Anzahl von BCC-Adressen pro Tag zu. Wegen des einzuhaltenden Datenschutzes ist es nicht erlaubt, eine Mail an viele Empfänger mit offenen Adressen zu senden, weil dann alle Empfänger die E-Mail-Adressen aller Empfänger sehen würden.
Das mit Visual Studio in C# geschriebene Programm SendMail sendet eine E-Mail jeweils einzeln an eine beliebig große Anzahl von Empfängern.
Inhaltsverzeichnis
![]() VS 2022 Projekt SendMail |
![]() Binary |
Eine Datei mit E-Mail-Adressen wird eingelesen und eine in einem beliebigen E-Mail-Programm entworfene Mail im HTML-Format wird über die Zwischenablage (Clipboard) in das Programm eingefügt. SendMail lauscht auf die Einfügung eines HTML-Dokuments in die Zwischenablage und übernimmt dies automatisch. Beim Senden wird jeder der eingelesenen E-Mail-Adressen eine eigene E-Mail gesendet. Zwischen dem Versand zweier E-Mail wird eine Pause eingefügt, für den Fall dass der Mail-Server es nicht mag, wenn Mails mit hoher Frequenz gesendet werden.
Für das Programm muss eine Textdatei mit folgenden Einträgen in der angegeben Reihenfolge hinterlegt sein:
| Zeile | Bedeutung | Beispiel |
|---|---|---|
| 1 | Pfad und Name der Datei mit der Liste der E-Mail-Adressen der Empfänger | C:\Users\ulli\Documents\Mail\Adressen.txt |
| 2 | Pfad und Name der Datei in die die Fehlermeldungen ausgegeben werden sollen | C:\Users\ulli\Documents\Mail\Fehler.txt |
| 3 | Name oder die IP-Adresse des Hostcomputers, der für SMTP-Transaktionen verwendet wird. | mail.gmx.net |
| 4 | Der Benutzername zur Anmeldung beim Host, meist die E-Mail-Adresse des Absenders | ulli@gmx.de |
| 5 | Das dazugehörige Passwort | geheim |
| 6 | Der mit der Adresse verbundenen Anzeigename | Ullis Roboter Seite |
| 7 | E-Mail-Adresse, an die eine Test-E-Mail gesendet werden soll | ulli@web.de |
| 8 | Zeitverzögerung zwischen dem Versenden zweier E-Mails in Millisekunden | 1000 |
Die Datei mit den obigen Beispieldaten sähe so aus:
C:\Users\ulli\Documents\Mail\Adressen.txt
C:\Users\ulli\Documents\Mail\Fehler.txt
mail.gmx.net
ulli@gmx.de
geheim
Ullis Roboter Seite
ulli@web.de
1000
Es gibt folgende Möglichkeiten, dem Programm die Konfigurationsdatei zuzuweisen.


Der Kommandozeilenparameter wird als erstes ausgewertet. Wurde keiner angegeben, wird versucht die Datei SendMailConfig.txt aus dem Arbeitsverzeichnis zu laden.
Die Adressenliste ist eine einfache Textdatei mit einer E-Mail-Adresse pro Zeile. Zeilen, die mit # (Rautezeichen) beginnen, werden ignoriert:
Nach dem Programmstart werden die Konfigurationsdatei und die Datei mit der E-Mail-Adressenliste eingelesen. Tritt hierbei ein Fehler auf, wird das Programm mit einer entsprechenden Meldung abgebrochen. Wenn alles korrekt eingelesen wurde, erscheint das folgende Fenster und das Programm wartet darauf, dass ein HTML-Dokument in die Zwischenablage eingefügt wird.
Am besten entwirft man die E-Mail in einem E-Mail-Programm wie Thunderbird im HTML-Format. Das Einfügen von Bildern ist möglich. Ist die E-Mail fertiggestellt und SendMail gestartet, markiert man den gesamten E-Mail-Inhalt (Strg+A) und kopiert ihn in die Zwischenablage (Strg+C). Nun werden der E-Mail-Text und die eingefügten Bilder übernommen. Die Übernahme wird durch ein Tonsignal quittiert.
Der Betreff kann über die Tastatur eingegeben oder hineinkopiert werden.
Wenn etwas Falsches übernommen wurde oder der Text noch einmal korrigiert werden muss, muss der bereits eingefügte Text vorher gelöscht werden. Der E-Mail-Inhalt wird nicht automatisch überschrieben.
Anschließend sollte die E-Mail an die Test-E-Mail-Adresse versendet werden (Schaltfläche Test). So lässt sich überprüfen, wie die E-Mail bei den Empfängern angezeigt wird.
Wenn die E-Mail wie vorgesehen angezeigt wird, kann sie an alle E-Mail-Adressen in der Adressenliste versendet werden (Schaltfläche Senden).
Die E-Mail-Adresse, an die die E-Mail erfolgreich versendet wurde, wird in die Liste Gesendet übertragen. Tritt beim Versenden ein Fehler auf, beispielsweise weil keine Verbindung zum Mail-Server hergestellt werden kann, wird die entsprechende E-Mail-Adresse in die Liste Fehler übernommen. Oberhalb beider Listen wird die Anzahl der Elemente angezeigt.
Fehlermeldungen wie Empfänger nicht gefunden oder Empfängerpostfach voll werden beim Versenden nicht vom Mail-Server zurückgemeldet. Dadurch scheint die E-Mail erfolgreich versendet worden zu sein. Der Mail-Server sendet aber in diesen Fehler eine Fehlermeldung per E-Mail an die Absender-Adresse.
Es kann versucht werden, die E-Mail an die Adressen, bei denen ein Fehler aufgetreten ist, ein weiteres Mal zu versenden. Über die Schaltfläche Fehler wiederholen werden die Adressen aus der Fehlerliste in die Versandliste übertragen.
Manche Mail-Server mögen es nicht, wenn E-Mails in hoher Frequenz versendet werden. Nach einer gewissen Anzahl nehmen sie dann keine neuen Mails mehr an. Deshalb wird zwischen dem Versand zweier E-Mails eine kurze Pause eingefügt. Wie lange diese sein soll, kann über die Konfigurationsdatei festgelegt werden. Die optimale Pausendauer muss individuell ausprobiert werden.
Das Formular Main ist das einzige Formular dieses Programm. Es liest die Konfigurationsdatei und die Adressliste ein. Es steuert den Versand der E-Mails.
Die Konfigurationsdaten werden bereits im Konstruktor eingelesen:
readonly bool configLoaded = false;
// ...
internal Main() {
InitializeComponent();
string[] args = Environment.GetCommandLineArgs();
if (args.Length > 1) {
fnConfig = args[1];
}
try {
sendMailConfig = SendMailConfig.FromFile(fnConfig);
configLoaded = true;
}
catch (Exception) {
MessageBox.Show("Konfiguarationsdatei '" + fnConfig + "' kann nicht eingelesen werden.",
"SendMail", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Kann die Datei nicht gefunden werden, bricht das Programm mit einer Fehlermeldung ab. Der Inhalt der Konfigurationsdatei wird nicht überprüft.
Die E-Mail-Adressenliste wird im Ereignis Form_Load eingelesen:
private void Form1_Load(object sender, EventArgs e) {
if (!configLoaded) { // Programmabbruch: Keine Konfiguration geladen
Close();
return;
}
NativeMethods.AddClipboardFormatListener(Handle);
string[] allAddresses;
try {
allAddresses = File.ReadAllText(sendMailConfig.addressListFilename).Split("\r\n");
}
catch (Exception) {
MessageBox.Show("Adressenliste '" + sendMailConfig.addressListFilename + "' kann nicht eingelesen werden.",
"SendMail", MessageBoxButtons.OK, MessageBoxIcon.Error);
Close();
return;
}
// ...
Der E-Mail-Inhalt wird in einem Steuerelement vom Typ WebBrowser angezeigt. Dieses Steuerelement ist in der Lage HTML-Dokumente anzuzeigen. Leider können die Inhalte nicht einfach geändert werden.
Die automatische Übernahme des E-Mail-Inhalts erfolgt durch eine überschriebene Fensterfunktion WndProc:
protected override void WndProc(ref Message m) {
const int WM_CLIPBOARDUPDATE = 0x31D;
if (wbMailDisplay.DocumentText is null || wbMailDisplay.DocumentText == "") {
if (m.Msg == WM_CLIPBOARDUPDATE) {
string clipboardData = Clipboard.GetText(TextDataFormat.Html);
if (!string.IsNullOrEmpty(clipboardData)) {
int index = clipboardData.IndexOf("<html");
if (index >= 0) {
clipboardData = clipboardData.Substring(index);
wbMailDisplay.DocumentText = clipboardData;
Console.Beep();
}
}
}
}
base.WndProc(ref m);
}
Die Nachricht vom Typ WM_CLIPBOARDUPDATE wird abgefangen und darauf untersucht, ob die Zwischenablage ein HTML-Dokument enthält. Der vom E-Mail-Programm gelieferte Mail-Code enthält meist noch einen Vorspann. Der HTML-Teil isoliert und an das WebBrowser-Steuerelement übergeben.
Das Überschreiben eines bereits eigelesenen Inhalts wird verhindert.
Um ein versehentliches Drücken der Schaltfläche Senden abzufangen, wird zunächst ein Dialog angezeigt, der zum Senden bestätigt werden muss.

Danach wird für jede eingelesene (in der Listbox lbToSend) Adresse die Methode MailSender.Send zum Versenden der Mail aufgerufen.
DialogResult dialogResult = MessageBox.Show("Mail jetzt senden?", "Mail versenden", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes) {
foreach (string recipient in lbToSend.Items) {
if (recipient != "") {
Exception? ex = MailSender.Send(recipient, tbSubject.Text, wbMailDisplay.DocumentText, sendMailConfig);
if (ex != null) {
// ... hier erfolgt die Fehlerbehanlung
// ... Schreiben in die Fehlerdatei
// ... Adresse in ListBox lbError übertragen
}
else {
// ... Versand erfolgreich
// ... Adresse in ListBox lbSend übertragen
}
}
// Frequenz herab setzen
Thread.Sleep(10000);
}
MessageBox.Show("Fertig!");
}
Die Klasse SendMailConfig dient zum Einlesen und Speichern der Konfigurationsdaten (siehe Abschnitt Konfiguration).

Die Klasse MailSender stellt die statische Methode Send zum Versenden von E-Mails bereit. Send benutzt eine SmtpClient-Instanz zum versenden der Mail. Nach und nach werden die zum Versand notwendigen Objekte erstellt und schließlich versendet.