Laden...

E-Mails versenden

Erstellt von C#ler vor 13 Jahren Letzter Beitrag vor 12 Jahren 9.485 Views
C
C#ler Themenstarter:in
48 Beiträge seit 2011
vor 13 Jahren
E-Mails versenden

Beschreibung:

Mit diesem Code kann man E-Mails versenden.
(Man ersetze die Angaben in den </>-Klammern durch den Wert!)


using System;
using System.Net;
using System.Net.Mail;
using System.Web;

...

public void sendmail()
{
            try
            {
                MailMessage mail = new MailMessage(new MailAddress(<Absender-E-Mail-Adresse>,<Absendername>), new MailAddress(<Empfänger-E-Mail-Adresse>, <Empfängername>));
                mail.Subject = <Betreff>;
                mail.Body = <Inhalt>;
                SmtpClient sc = new SmtpClient(<SMTP-Server-Adresse Absender>, <Port>);
                sc.UseDefaultCredentials = false;
                sc.Credentials = new NetworkCredential(<Absender-E-Mail-Adresse>, <Absender-Passwort>);
                sc.Send(mail);
                MessageBox.Show("E-Mail erfolgreich gesendet.");
            }
            catch (Exception)
            {
                MessageBox.Show("Fehler beim Senden der E-Mail.");
            }
}

Schlagwörter: E-Mail, EMail, Email, Senden, SMTP, NetworkCredential, System.Net, System.Web, MailMessage

In theory, there is no difference between theory and practice. But, in practice, there is.

The nice thing about the Java API is that if you don't like it, just wait two minutes — it will change. Doug Lyon

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo C#ler,

danke für das Snippet. Ich denke, da steckt noch einiges an Verbesserungspotenzial drin. So wie es jetzt ist, müssten man den Code für verschiedene Empfänger immer kopieren und dann die Werte direkt im Code füllen. Besser wäre es die Werte per Parameter zu übergeben.

Leider hat man dann eine lange Liste von String-Parametern und kann beim Aufruf leicht verwechseln, ob nun zuerst den Empfänger kommt und dann der Absender oder andersherum. Wenn du sprechende Parameternamen verwendest, kann man aber als Aufrufer ab C# 4.0 wenigstens benannte Parameter verwenden. Bei der Gelegenheit könntest du dann bestimmte Parameter auch optional machen, z.B. den Port (oder sogar den Body, denn für manche Zwecke reicht es ja, nur den Betreff zu verwenden.

Um das Problem mit der langen Parameter-Liste (für C# < 4.0) zu beheben, könntest du eine Klasse EMail o.ä. schreiben, die für jeden Parameter eine passende Property besitzt. So kann der Aufrufer seine Werte in die Properties füllen und dann das fertige Objekt an deine Methode übergeben oder du machst die Methode gleich zur Instanzmethode der Klasse.

herbivore

C
C#ler Themenstarter:in
48 Beiträge seit 2011
vor 13 Jahren

Also, v2.0


class Mail
{
public string sendAddress, sendName, receiveAddress, receiveName, subject, body, smtp, password;
public int port;
public Mail(string sendAddress, string sendName,string receiveAddress, string receiveName, string subject, string body, string smtp, string password, int port)
{
this.sendAddress = sendAddress;
this.sendName = sendName;
this.receiveAddress = receiveAddress;
this.receiveName = receiveName;
this.subject = subject;
this.body = body;
this.smpt = smtp;
this.password = password;
this.port = port;
}
public void sendmail(Mail m)
{
            try
            {
                MailMessage mail = new MailMessage(new MailAddress(m.sendAddress,m.sendName), new MailAddress(m.receiveAddress, m.receiveName));
                mail.Subject = m.subject;
                mail.Body = m.body;
                SmtpClient sc = new SmtpClient(m.smtp, m.port);
                sc.UseDefaultCredentials = false;
                sc.Credentials = new NetworkCredential(m.sendAddress, m.password);
                sc.Send(mail);
                MessageBox.Show("E-Mail erfolgreich gesendet.");
            }
            catch (Exception)
            {
                throw new MailException("Fehler beim Senden der E-Mail.");
            }
}
public MailException : Exception
{
public MailException(string message) : base(message) { }
}
}

In theory, there is no difference between theory and practice. But, in practice, there is.

The nice thing about the Java API is that if you don't like it, just wait two minutes — it will change. Doug Lyon

1.552 Beiträge seit 2010
vor 13 Jahren

Wobei immer noch das Problem besteht dass du alle Parameter angeben musst. Dies wäre bei folgendem nicht der Fall:


public Mail(string sendAddress,string sendName = null, string receiveAddress)
{[...]}

dies könnte wie folgt aufgerufen werden.


new Mail("aaa");
new Mail("aaa","bbb");
new Mail("aaa","bbb","ccc");
new Mail("aaa",receiveAddress:"ccc");

Wobei dann immer noch das ewig lange Konstructor schreiben ist.
Kürzer gings dann wie herbivore sagt mit Properties


public class Mail
{
    public SendName{get;set;}
    public SendAddress{get;set;}
    public ReceiveAddress{get;set;
}

welches dann wie folgt aufgerufen werden kann.


Mail m = new Mail();
m.SendName = "...";

Wie du es dann machst ist nicht so tragisch, schlimmer finde ich die sendmail Methode. Sie ist eine Methode in der Mail Klasse und nicht statisch. Wenn sie statisch wäre, wäre es eine andere Angelegenheit. Die sendmail methode wird immer auf einem Object des Typs Mail aufgerufen. Warum übergibst du dann ein Mail Object. Normalerweise sollte die sendmail Methode jene Mail versenden auf welche die Methode aufgerufen worden ist. Denn bei dir ist folgendes möglich:


Mail m1 = new Mail();
Mail m2 = new Mail();
m1.sendmail(m2);
m2.sendmail(m2);

Wobei dann logischerweise beidesmal m2 versendet wird, aber nicht sollte.
Besser wäre es wenn du es wie folgt hättest:


Mail m1 = new Mail();
Mail m2 = new Mail();
m1.sendmail();
m2.sendmail();

public class Mail
{
    public void sendmail(){...}
}

Dann wäre schlussendlich noch ein Vorschlag zu dem trow: Als Benutzer der Methode sieht man leider nur dass ein Fehler aufgetreten ist aber nicht welcher. Entweder sollte deine Exception-Klasse geändert werden dass der base Contructor 2.Überladung von Exception(string message,Exception innerException) aufgerufen werden (inner Exception wäre der Fehler der im try Block geworfen wird) oder du solltest die exception die in sendMail geworfen wird nicht abfangen und nach oben werfen.

Ich hoffe ich konnte es verständlich genug erklären.

Gruß
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

1.820 Beiträge seit 2005
vor 13 Jahren

Hallo!

Und dann gibt's noch das "Problem" mit den exceptions.
Du fängst einfach alle ab, und erstellst dafür eine neue. In der aufrufenden Methode besteht dann keine Möglichkeit mehr, den aufgetretenen Fehler zu spezifizieren. Zumindest sollte die ursprüngliche Exception mit übergeben werden (InnerException).

EDIT: Nach interner Diskussion mit herbivore angepasst

Nobody is perfect. I'm sad, i'm not nobody 🙁

699 Beiträge seit 2007
vor 13 Jahren

Hallo C#ler,

ich sehe bei Dir einige Fehler, die ich anfangs auch gemacht habe. Abgesehen von den obigen Kommentaren, kommt noch folgendes hinzu:
*MessageBox.Show() gehört in die GUI rein. Wenn Du in der Klasse ausgaben machen möchtest, dann kannst Du das über Events nach außen geben [FAQ] Eigenen Event definieren / Information zu Events , so kann der Anwender der Klasse, dann selbst entscheiden, was er mit der Meldung machen will.
Für dich als Developer, gehen auch Präprozessordirektiven in denen Du dann Debug Meldungen in das Visual Studio Ausgabefenster schreiben kannst. #if (C#-Referenz), oder meistens auch ausreichend die Debug-Methoden. *Du übernimmst die Werte im Konstruktor ungeprüft. Es macht wenig sinn, wenn man eine Mail versenden möchte, das man einen leeren SmtpUserName angeben kann. Dies sollte man dann sofort mit einer ArgumentException dem aufrufer melden. *DIe SmtpClient Klasse nutzt Unmanaged Methoden. Diese muss man nach der verwendung mit Dispose wieder freigeben. Lese Dir da mal zu der SmtpClient.Dispose() Methode und using-Anweisung die MSDN durch. Da hast Du dir nämlich eines der guten Beispiele der MSDN ausgesucht, wo das Thema Dispose sehr gut erklärt wird.

Als anmerkung zu deiner Exception Klasse noch. Ich hab mir das so angewöhnt, wenn ich Exceptions nicht selbst und direkt behandeln kann in meiner Klasse, lasse ich die laufen und werfe die nur weiter nach oben. So muss sich dann der aufrufer um das Problem kümmern und kann wiederum selbst entscheiden, was er damit machen will.
Eigene Exception Klassen verwende ich nur, wenn innerhalb meiner Klasse neue Exception entstehen können, die ich dann nach oben melden möchte, sofern es in der MSDN dazu noch keine fertigen Exception schon gibt, die das Problem behandeln (siehe ArgumentException).

So das sollte Dir dann noch weiterhelfen, um die Klasse besser zu designen.

Grüße Stephan

I
19 Beiträge seit 2010
vor 12 Jahren

Respekt, wie viel konstruktive Kritik auf das Thema folgt.
Bin auf die Änderungen gespannt.
👍