C# Email aus Programm versenden

alebec7

Ensign
Registriert
Juni 2008
Beiträge
154
Ich bin gerade dabi, einen Formular zum versenden von E- Mails zu erstellen, aber es will nicht gelingen. Hier der Quellcode:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Mail;
using System.Net;
using System.Web;

namespace mail
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}


private void button1_Click(object sender, EventArgs e)
{
try
{
// erzeugen der Mail
MailMessage message = new MailMessage();

message.From= new MailAddress("test@googlemail.com");
message.To.Add("andereemail@t-online.de");
message.Subject = "betreff";
message.Body = "inhalt";

SmtpClient client = new SmtpClient("smtp.googlemail.com",465);

// Authentifizierung
client.Credentials= new NetworkCredential ("test@googlemail.com","pw");


client.EnableSsl = true;

// senden
client.Send(message);

MessageBox.Show("Nachricht wurde gesendet! \n Vielen Dank für ihr Reporting!");
}

catch (SmtpException exeption)
{
MessageBox.Show(exeption.Message);

}
}

}
}

Und bitte keine Verwiese auf Suchmaschinen, das habe ich schon getan!
 
welche .net / c# version verwendest du denn?
 
Zuletzt bearbeitet:
Ich verwende die MS Visual C# 2008 Express Edition mit Framework 3.5 und SP.
 
bekommst du irgendeine exception oder kommt einfach keine email an?
 
Er sagt: "Timeout für den Vorgang wurde überschritten".
Das lässt mich vermuten, dass die authentifizierung scheitert. Ich habe etwas darüber gelesen, dass man erst ein Zertifikat erstellen muss (oder so ähnlich^^).
 
schoneinmal einen anderen provider als google probiert?
 
Versuch's mal ohne SSL, d.h. Port 25 und nicht 465. Ob der bei Google Mail allerdings offen ist, weiß ich nicht.
Ansonsten musst Du mal schauen, wie Du mit der Bibliothek SSL hinbekommst.
 
Wenn ichs mit t-online probiere kommt nur: "Fehler beim senden der Mail".
 
Ich habe den Port gerade mal bei Googlemail auf 25 geändert. Und siehe da, es funktioniert!
 
Ich entschuldige mich jetzt schon für den 3. Post, aber beim Versuch eine Progressbar einzubauen gibt es ein problem. Wenn ich das Programm starte und den Sende- Button klicke, bricht er mit der Fehlermeldung:

"Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement cb_subject erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde."

ab. Wenn ich anstatt message.Subject = cb_subject.Text; (Comboboxinhalt) nur einen string einschreibe geht alles gut, d.h. die Progressbarläuft und die Mail wird versendet.

Ich hoffe ihr könnt mir weiterhelfen.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Mail;
using System.Net;
using System.Web;
using System.Net.Security;
using System.Net.Sockets;
using System.Threading;

namespace mail
{
public partial class Form1 : Form
{

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
cb_subject.SelectedIndex = 0;
}

private void rtb_body_Click(object sender, EventArgs e)
{
if (rtb_body.Text.Length <= 48)
{
rtb_body.Text = "";
}

}

private void button2_Click(object sender, EventArgs e)
{
bgw1.RunWorkerAsync();
}

private void UpdateMyProgressbar(int value)
{
pgb1.Value = value;
}

private delegate void DelegateUpdateProgress(int value);
public void myBackgroundworker_DoWork(object sender, DoWorkEventArgs e)
{
DelegateUpdateProgress myProgress = new DelegateUpdateProgress(UpdateMyProgressbar);
for (int i = 99; i < 100; i++)
{
//Hier der Prozess

try
{
// erzeugen der Mail
MailMessage message = new MailMessage();

message.From = new MailAddress("test@googlemail.com");
message.To.Add("test@googlemail.com");
message.Subject = cb_subject.Text; //cb_subject.Text;
message.Body = "Inhalt"; //rtb_body.Text;
//message.Body = ""; //hier kommt der name des users rein, welcher die nachricht sendete

SmtpClient client = new SmtpClient("smtp.googlemail.com", 25);

// Authentifizierung
client.Credentials = new NetworkCredential("test@googlemail.com", "pw");

client.EnableSsl = true; //SSL einschalten

// senden
client.Send(message);

}

catch (SmtpException exeption)
{
MessageBox.Show(exeption.Message);
}

//Aktualisieren der Progressbar
pgb1.Invoke(myProgress, i);
}
}

private void bgw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Nachricht wurde gesendet! \n Vielen Dank für ihr Reporting!", "Hinweis!");
}

}

}
 
1. Du kannst ruhig ein neues Thema aufmachen da es ja auch ein neues ist ;)

2. Die meldung kommt weil du aus einem anderen Thread schreiben willst (na lesen kannst wohl ;) ), das ist jedoch seit .net 2 nicht mehr erlaubt. (in 1.1 war es nur schlecht implemtiert/geduldet).

In englisch heist das "Cross-Thread operation"

In .net 3.5 kannst du dafuer einen generic delegate verwenden.

Code:
        delegate void GenericDelegate();
         void UpdateProgressBarForUserNotification()
        {
            GenericDelegate dlg = delegate()
            {
                updateProgessBar.Enabled = false;
                progressBar1.Value = (progressBar1.Value % progressBar1.Maximum) + 1;
                updateProgessBar.Enabled = true;
            };
            progressBar1.Invoke(dlg);
        }

so sollte es klappen ;)

EDIT: Du kannst auch i wieder uebergeben wenn du willst, besser ist aber einfach einen timer zu starten der alle sek. die Progressbar "aktualisiert".

EDIT2: Und installiere dir die engl. Version von VS, so findet du viel mehr und viel leichter wenn du im Google suchen musst. (Weil die Fehlermeldungen dann auch engl. sind ;) )

Und findest den unterschied zwischen meiner delegate implemtierung und Deiner? Deine ist nur nicht vollstaendig.
 
Zuletzt bearbeitet:
Könntest du bitte deinen Quellcode in meinen einfügen? Ich habs probiert, aber es kommt immernoch der Threadfehler. Und was meinst du mit: "updateProgessBar.Enabled = false;"? Meinst du damit die Progressbar (pg1 in meinem Programm)?
 
alebec7 schrieb:
Könntest du bitte deinen Quellcode in meinen einfügen? Ich habs probiert, aber es kommt immernoch der Threadfehler. Und was meinst du mit: "updateProgessBar.Enabled = false;"? Meinst du damit die Progressbar (pg1 in meinem Programm)?

sry,

Code:
delegate void GenericDelegate();
         void UpdateProgressBarForUserNotification()
        {
            GenericDelegate dlg = delegate()
            {
               // updateProgessBar.Enabled = false; //Hier Stoppe ich meinen timer
                pgb1.Value = (pgb1.Value % pgb1.Maximum) + 1;
                //updateProgessBar.Enabled = true;//Hier Starte ich meinen timer
            };
            pgb1.Invoke(dlg);
        }

dann wuerde ich deinen COde so ausfuehren:
Code:
...
//Aktualisieren der Progressbar
//pgb1.Invoke(myProgress, i);
UpdateProgressBarForUserNotification();
.
.
.

so sollte es klappen, falls probleme auftauchen nochmal melden.

Ich habe es dir nun mit meiner implementierung gezeigt. Waere schoen wenn du es nun auch mit deiner schaffst, wie gesagt du hast es fast richtig. ;)

EDIT: dlg , ist eine Dialog instanze von mir. du hast vermutlich eine Form ?
 
1.) Das bei der Email wird an der Authentifizierung scheitern. Normalerweise funktioniert es, wenn man den eigenen Internet Provider angibt und eine beliebige Absenderadresse. Passwort ist normalerweise nicht erforderlich, genauso wenig muss einem die Absenderadresse gehören. Manche Provider überprüfen das jedoch aus Anti Spam Gründen.
Es kann auch gut sein, dass man beim Empfänger im Spam Ordner landet, weil der Absender Server nicht die IP hat, die im DNS Record der Absender Domain steht.
Eine wirklich gute Möglichkeit gibt es soviel ich weiß nicht bzw. wird immer von der EDV Umgebung abhängen. Unser Exchange Server kübelt z.B. alles, was er für verdächtig hält.

2.) Ich löse das mit der Progressbar immer durch eine globale Variable, die den Zustand speichert und einen Thread, der alle 100ms das GUI aktualisiert, die Ausgabe einfügt etc. Das löst nicht nur das Problem mit den Threads, sondern steigert meistens auch die Performance. Wenn ich z.B. eine Datei einlese alle paar Byte das Control aktualisieren muss, Textfelder ändern etc., dann ist das nicht unbedingt sehr performant.
Bei einem Multiline Textfeld oder Richtext Control dauert es auch sehr lange, wenn darin schon 100K Zeilen Text stehen und man 100 Zeilen hintereinander einfügen will. Da ist es deutlich schneller, wenn man 100ms alle zusammen wartet und dann den ganzen Text auf einmal rein schießt.
Gerade der Status einer ProgressBar ist etwas, wo man es mit der Thread Synchronisations nicht so genau nehmen muss. Wenn da einmal alle 100 Jahre eine Operation verloren geht und diese 1 Byte zu wenig anzeigt, dann wird das niemanden umbringen. Wenn nur ein Thread schreibt und einer liest, dann kann es bei einem Integer auch zu keinen Problemen kommen. Bei einer Textausgabe verwende ich immer Synchronized Queues. Ich fülle einfach an beliebigen Stellen ein und im Timer lese ich es in einer While Schleife aus. Hier ist auch der schlimmste Fall, dass eine Message erst 100ms später dran kommt, solange man nur einen Thread hat, der das Dequeue verwendet.
Das hat wieder den Vorteil, dass man eine Stelle hat, an der GUI Ausgaben passieren und an der man eventuell etwas mitloggen kann.

While(OutQueue.Count>0)
Message&=OutQueue.Dequeue()
End While
RTF_Out.AppendText(Message)

P.S.: Bei der Progressbar muss man aufpassen, dass man nicht irrtümlich den Wert zu hoch oder zu niedrig ansetzt. Ich mache das immer so, dass ich zuerst noch überprüfe, ob der aktuelle Wert auch nicht zu groß ist und wenn ja, dann stelle ich den aktuellen Wert auf maxvalue. Es ist besser der Progressbar ist falsch, als die ganze Applikation funktioniert nicht mehr.
Falls sich maxvalue ändert, so ändere ich den aktuellen Wert zuerst auf Minvalue und dann auf den Wert, den er haben soll.
 
@ andr_gin:

Deine While- Schleife sieht mir sehr nach VB aus? Ich benutze aber C#. Und was ist "OutQueue"?

EDIT: Jetzt geht die Progressbar gar nicht mehr und er sgat immernoch Threadfehler:

Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Mail;
using System.Net;
using System.Web;
using System.Net.Security;
using System.Net.Sockets;
using System.Threading;

namespace mail
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            cb_subject.SelectedIndex = 0;
        }

        private void rtb_body_Click(object sender, EventArgs e)
        {
            if (rtb_body.Text.Length <= 48)
            {
                rtb_body.Text = "";
            }

        }

        private void button2_Click(object sender, EventArgs e)
        {
            bgw1.RunWorkerAsync();
        }

        private void UpdateMyProgressbar(int value)
        {
            pgb1.Value = value;
        }

        delegate void GenericDelegate();
            void UpdateProgressBarForUserNotification()
            {
            GenericDelegate dlg = delegate()
                {
                    //pgb1.Enabled = false;
                    pgb1.Value = (pgb1.Value % pgb1.Maximum) + 1;
                    //pgb1.Enabled = true;
                };
                pgb1.Invoke(dlg);
                            
            }
        
        private delegate void DelegateUpdateProgress(int value);
        public void myBackgroundworker_DoWork(object sender, DoWorkEventArgs e)
        {
            DelegateUpdateProgress myProgress = new DelegateUpdateProgress(UpdateMyProgressbar);
            
            {
                //Hier der Prozess
                try
                {
                    // erzeugen der Mail  
                    MailMessage message = new MailMessage();

                    message.From = new MailAddress("test@googlemail.com");
                    message.To.Add("test@googlemail.com");
                    message.Subject = cb_subject.Text;         //Combobox
                    message.Body = rtb_body.Text;              //Richtextbox
                    //message.Body = "";  //hier kommt der name des users rein, welcher die nachricht sendete

                    SmtpClient client = new SmtpClient("smtp.googlemail.com", 25);

                    // Authentifizierung  
                    client.Credentials = new NetworkCredential("test@googlemail.com", "pw");

                    client.EnableSsl = true;        //SSL einschalten  

                    // senden  
                    client.Send(message);
                                                            
                }

                catch (SmtpException exeption)
                {
                    MessageBox.Show(exeption.Message);
                }

                //Aktualisieren der Progressbar
                UpdateProgressBarForUserNotification();
            }
        }

        private void bgw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            MessageBox.Show("Nachricht wurde gesendet! \n Vielen Dank für ihr Reporting!", "Hinweis!");
        }

    }

}
 
Zuletzt bearbeitet:
andr_gin schrieb:
Falls sich maxvalue ändert, so ändere ich den aktuellen Wert zuerst auf Minvalue und dann auf den Wert, den er haben soll.

Das kannst dir in Zukunft sparen wenn du folgenden Code zum Aktualisieren der Progressbar verwendest.
Code:
pgb1.Value = [B](pgb1.Value % pgb1.Maximum)[/B] + 1;

alebec7 schrieb:
@ andr_gin:

EDIT: Jetzt geht die Progressbar gar nicht mehr und er sgat immernoch Threadfehler:

bitte lass mir deine code zukommen, dann schau ich nochmal rein.

Funktionieren muss es , habe ich schon mehrfach so implementiert.
 
Der aktuelle Code steht 2 Posts über diesem...
 
alebec7 schrieb:
Der aktuelle Code steht 2 Posts über diesem...

Nun, habe aber keine lust ein projekt anzulegen und alle objekte zu erzeugen.
Ich kann dir nur anbieten zu helfen, wenn du dein Project nicht zippen willst und mir schicken ... Auch ok dann halt ned. ;)

EDIT: Kommentiere mal diese zeile aus.
Code:
DelegateUpdateProgress myProgress = new DelegateUpdateProgress(UpdateMyProgressbar);
 
Zuletzt bearbeitet:
Zuletzt bearbeitet:
So, habe nun den Fehler gefunden und geloest.

Ja Du hast recht, die CrossThreading Exception kommt noch immer, nur hast du vergessen zu sagen das sie nicht beim Update der Progressbar kommt. (Debuggen zu koennen ist das a und o beim poggen)

Nun, die Exception kommt bei Zeile 91,
Code:
message.Subject = cb_subject.Text; //cb_subject.Text;         //Combobox

Was klar ist, da du vom Form einen Wert im Backgroundworker (im Message object) setzen willst.
Sprich das musst Du mit einem Invoke machen dann klappt es auch ;)

und ich moechte dir die Loesung nun nicht auf die Nase binden, bitte erst mal selbst versuchen.

Noch eine Frage dazu , hat es einen besondern Grund warum du nicht das SendAsync der class SmtpClient verwendest? (Das ist der 2. Loesungsansatz.)
 
Zurück
Oben