Avatar billede pablopablo Nybegynder
03. oktober 2008 - 10:29 Der er 32 kommentarer

Send mail via dot net

Hejsa...

Jeg har lige et sprøgsmål ang. System.Net.Mail.SmtpClient Send og SendAsync som jeg ikke kan finde har på MSDN :(

Det burde være oplagt hvad forskellen er på Send og SendAsync. SendAsync blokkere naturligvis ikke hovedtråden - thats it.

Men der står også i dokumentationen følgende:

"After calling SendAsync, you must wait for the e-mail transmission to complete before attempting to send another e-mail message using Send or SendAsync."

Hva faen...hjælper det så at bruge SendAsync? Og mit egentlige spørgsmål, hvordan vil de have at man skal vente?

Jeg bruger pt. en løkke struktur til at sende mails ud og derfor kan det jo let opstår at den ikke er færdig med at sende når den kalder SendAsync metoden kort tid efter igen...burde det ikke være det smarte i det async at man ikek skulle vente på noget... eller det er bare mig???

Håber meget I kan hjælpe mig!

Mvh. PabloPablo
Avatar billede pablopablo Nybegynder
03. oktober 2008 - 10:36 #1
hhmm...måske er svaret, at man skal tilføje alle email adresser man ønsker at sende til på en gang...i stedet for at kalde Send /SendAsync for hver email - som jeg pt. gør ;) fandt nemlig lige dette: http://weblogs.asp.net/scottgu/archive/2005/12/10/432854.aspx
Avatar billede pablopablo Nybegynder
03. oktober 2008 - 10:46 #2
Problemet er bare, at jeg også har brug for en ny:
ListDictionary replacements = new ListDictionary();

for hver eneste mail, så nej det var ikke løsning...så er det formentlig kun en ting tilbage...og det er at lytte på completeEventHandlere og først kalde send metode fra den hver gang...hvis i har nogle bedre forslag...så er i stadig meget velkomne!
Avatar billede flashit Nybegynder
03. oktober 2008 - 15:41 #3
Avatar billede pablopablo Nybegynder
03. oktober 2008 - 17:15 #4
Hej igen...har lige set den, men den forklare blot hvad jeg tidligere har gjort. Når man sender til multiple modtagere, så er det vel ikke muligt også at bruge:

ListDictionary replacements = new ListDictionary();

for hver eneste brugere. Jeg har nemlig brug for at indsætte/udskifte div. TAGS i min HTML skabelon med det rigtige brugernavn og kodeord...således at alle modtager en mail med de rigtige informationer.
Avatar billede arne_v Ekspert
04. oktober 2008 - 03:24 #5
SendAsync sparer vil dig for selv at lave multithreaded programmering.

Men til dit formål tror jeg at jeg ville lave en ThreadPool og hvor hver email
sendes ud med en 50-100 på BCC via normal Send ikke SendAsync.
Avatar billede pablopablo Nybegynder
05. oktober 2008 - 03:12 #6
Hej Arne...men mit problem er jo netop, at jeg ønsker at sende en specifik mail ud til hvér eneste af mine eks. 500 brugere... Idet at C# koden sammensætter mail for hver bruger, således at den indeholder dynamisk indsat data...såsom brugernavn, kodeord mv....

Nedenfor kan du se min nuværende kode...det virker delvist...dvs. idet at jeg har rigtig mange brugere at jeg skal sende til, så melder asp.net TimeOut...idet default er sat til 90s...i know...har også prøvet at sætte timeout til time...og jo det gør en forskel...men det fejlede alligevel til sidst og det virker ikke som om, at det er den optimale måde... dvs. at kalde send metoden 500 gange for at udsende 500 emails...men findes der reelt andre muligheder, når de fysiske mails nu ikke er ens...??

for (int i = 0; i < ListBox1.Items.Count; i++)
                {
                    if (ListBox1.Items[i].Selected == true)
                    {
                        try
                        {
                            ListDictionary replacements = new ListDictionary();
                            replacements.Add("<%UserName%>", ListBox1.Items[i].Value);

                            if (DropDownList1.SelectedItem.ToString().ToLower() != "test")
                                replacements.Add("<%Password%>", Membership.GetUser(ListBox1.Items[i].Value).GetPassword());

                            replacements.Add("<%date_da%>", DateTime.Now.ToShortDateString());
                            replacements.Add("<%UserEmail%>", ListBox1.Items[i].Text);

                            System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient(Session["SmtpServer"].ToString());
                            smtp.Credentials = new NetworkCredential(Session["InfoEmail"].ToString(), "kode");

                            md.BodyFileName = Server.MapPath("../HTML/Newsletter_" + selectedUserLanguage[i].ToString() + ".htm");
                            System.Net.Mail.MailMessage mm = md.CreateMailMessage(ListBox1.Items[i].Text, replacements, this);
                            mm.BodyEncoding = System.Text.Encoding.UTF8;
                            smtp.Send(mm);
                        }
                        catch (Exception)
                        {
                            hfInvalidEmails.Value += ListBox1.Items[i].Text + "\n";
                        }
                    }
                }
Avatar billede arne_v Ekspert
12. oktober 2008 - 04:48 #7
Hvis det er individuelle email, så skal der naturligvis kun sendes til en bruger.

Og timeout kan kun løses the hard way:
- kør en 25-50 tråde parallelt som sender emails
- sæt timeout op ellrt bedre: kør det i en windows service eller utility app fremfor fra en ASP.NET side
Avatar billede pablopablo Nybegynder
12. oktober 2008 - 13:58 #8
Hej Arne...

Jeg har faktisk været ved at lave det i en winform...men jeg kunne ikke få det til at virke, idet at jeg ikke kunne tilgå de nødvendige klasser/namespaces som bruges til at det her mail halløj...?

Kan du få ovenstående kode til at kompilere i en winform...??

Mvh. PabloPablo
Avatar billede arne_v Ekspert
12. oktober 2008 - 15:44 #9
.NET email er helt uafhængig af app type - du kan sagtens sende email fra en win form.

Det du skal rette er:
- ikke Server.MapPath til at finde fil med
- nogle andre GUI kontroller
Avatar billede arne_v Ekspert
28. oktober 2008 - 02:29 #10
OK ?
Avatar billede pablopablo Nybegynder
28. november 2008 - 02:17 #11
Jeg har brug for at bruger MemberShip klassen, derfor har jeg tilføjer en app.config fil hvori jeg har angivet en connectionstring...men når jeg kører programmet får jeg følgende fejl...

"Failed to generate a user instance of SQL Server due to a failure in starting the process for the user instance. The connection will be closed."

"ved System.Web.Management.SqlServices.GetSqlConnection(String server, String user, String password, Boolean trusted, String connectionString)\r\n  ved System.Web.Management.SqlServices.SetupApplicationServices(String server, String user, String password, Boolean trusted, String connectionString, String database, String dbFileName, SqlFeatures features, Boolean install)\r\n  ved System.Web.Management.SqlServices.Install(String database, String dbFileName, String connectionString)\r\n  ved System.Web.DataAccess.SqlConnectionHelper.CreateMdfFile(String fullFileName, String dataDir, String connectionString)\r\n  ved System.Web.DataAccess.SqlConnectionHelper.EnsureSqlExpressDBFile(String connectionString)\r\n  ved System.Web.DataAccess.SqlConnectionHelper.GetConnection(String connectionString, Boolean revertImpersonation)\r\n  ved System.Web.Security.SqlMembershipProvider.GetUser(String username, Boolean userIsOnline)\r\n  ved System.Web.Security.Membership.GetUser(String username, Boolean userIsOnline)\r\n  ved System.Web.Security.Membership.GetUser(String username)\r\n…


Har googlet denne: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3964738&SiteID=1

Men kan ikke få det til at virke, har du en ide til hvad det kan være?

min app.config ser således ud:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 
    <connectionStrings>
      <remove name="LocalSqlServer"/>
      <add name="ScannetCS" connectionString="Server=XXXXXX; Database=XXXXXX; User ID=XXXXXX; Password=XXXXXX; User Instance=False;" providerName="System.Data.SqlClient"/>
    </connectionStrings>
    <system.web>
      <membership defaultProvider="AspNetSqlMembershipProvider" userIsOnlineTimeWindow="15" >

        <providers>

          <clear />
          <remove name="AspNetSqlMembershipProvider"/>
          <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ScannetCS" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="/" requiresUniqueEmail="true" passwordFormat="Encrypted" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="4" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression=""/>
         
        </providers>

      </membership>
    </system.web>

</configuration>
Avatar billede arne_v Ekspert
30. november 2008 - 04:13 #12
Røg den kommentar i den rigtige tråd ?
Avatar billede pablopablo Nybegynder
01. december 2008 - 07:22 #13
ja :)
Avatar billede pablopablo Nybegynder
01. december 2008 - 12:11 #14
Hej igen Arne.

Jeg har efterhånden konstueret et lille mail program som fungere nogenlunde...dvs. det kan sende mails... :) Men hvis jeg fx. ønsker at sende 10 mails samtidigt og bare en af mail adresserne ikke findes, ja så opståer der jo en exception og i mellemtiden står programmet og hænger...programmer "fryser" generelt i hele den periode som det nu tager at sende div. mails afsted, uanset om alle modtagere findes eller ej...
Jeg har to status progressbarer, samt nogle labels som jeg bruger til at vise brugeren hvor mange mail som pt. er afsted korrekt og hvor mange som fejlede...de virker...men ikke helt efter hensigten...UI opdaterer nemlig før til allersidst...og det er naturligvis ikke optimalt.

Mine spørgsmål er nu følgende:

- Hvordan kan jeg gøre så programmet ikke "hænger" så meget i det?
- Hvordan gør jeg så winformens UI opdateres løbende? ( Jeg har prøvet med metoderne: Invalidate og Update, men det får kun programmet til at gå helt kold :( )

Du kan se min komplette kode her:

http://www.unicdesign.dk/mail.txt

Håber virkelig meget at du kan hjælpe mig, for har virkelig bøvlet meget med det...
Avatar billede pablopablo Nybegynder
03. december 2008 - 15:12 #15
Arne..? help me please...
Avatar billede arne_v Ekspert
04. december 2008 - 03:08 #16
Ingen anelse. Du sender emails i separate tråd. Så bør GUI ikke hænge.

Hvis du skal have noget fornuftigt progress skal du nok opdatere noget hver gang en tråd er færdig
(Join er returneret).
Avatar billede arne_v Ekspert
04. december 2008 - 03:08 #17
Hov.

while (!workerThread.IsAlive);

duer ikke !!!!
Avatar billede arne_v Ekspert
04. december 2008 - 03:10 #18
Der skal ikke bruges not og det semikolon skal slettes.

while (workerThread.IsAlive)
    Thread.Sleep(1);
Avatar billede arne_v Ekspert
04. december 2008 - 03:12 #19
Øh.

Naturligvis hænger den.

Du starter en tråd i din button click. Og det er helt fint.

Men så laver du Join på den i samme button click. Og så har du mistet hele fordelen
ved at starte en tråd.

Det går ikke.

Redesign !
Avatar billede pablopablo Nybegynder
04. december 2008 - 09:44 #20
Hej Arne! Tak for dine input...men er ikke helt med har blot fulgt dette eksempel fra MSDN: http://msdn.microsoft.com/en-us/library/7a2f3ay4(VS.80).aspx

Gider du ikke vise mig hvordan du ville designe koden, så den køre så optimalt som muligt?

På forhånd tak!
Avatar billede pablopablo Nybegynder
09. december 2008 - 17:11 #21
Arne?
Avatar billede arne_v Ekspert
10. december 2008 - 04:06 #22
Du laver en knap som ved klik starter 1 eller N tråde og derefter returnerer
med det samme, disse tråde sender hver en stribe emails og opdaterer GUI med
hvor langt de er kommet.
Avatar billede pablopablo Nybegynder
10. december 2008 - 11:07 #23
undskyld, men det er jo det jeg har prøvet på...men det virker jo ikke...det hænger jo i koden...
Avatar billede arne_v Ekspert
10. december 2008 - 15:05 #24
Du laver Join i din klik kode.
Avatar billede pablopablo Nybegynder
10. december 2008 - 15:14 #25
Ja har som sagt fulgt MS vejledning...det er sådan de gør??

Du skrev også tidligere at: while (!workerThread.IsAlive); ikke duer...?

Kan jeg ikke få dig til at vise mig det kode som du mener vil virke?
Avatar billede arne_v Ekspert
12. december 2008 - 03:08 #26
Den MS kode du linker til er en console app. Fordi noget kan kaldes i en console
app behøver det ikke at være godt at kalde i noget button click kode.

Busy wait er noget griseri og jeg undrer mig en del over at MS vil lægge navn
til sådan noget kode.

Måske kan jeg brygge et eksempel i weekenden.
Avatar billede pablopablo Nybegynder
12. december 2008 - 12:17 #27
Okay, ja det viste jeg intet om :( ?

Det lyder bare super Arne, det vil jeg se meget frem til! På forhånd tak!
Avatar billede arne_v Ekspert
13. december 2008 - 05:16 #28
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace E
{
    public class MailJob
    {
        public String To { get; set; }
        public String Subject { get; set; }
        public String Body { get; set; }
    }
    public class Program
    {
        [STAThread]
        private static void Main(string[] args)
        {
            Queue<MailJob> q = new Queue<MailJob>();
            for(int i = 0; i < 50; i++)
            {
                q.Enqueue(new MailJob { To="arne@arne", Subject="Test", Body="This is a test" });
            }
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm(q));
        }
    }
}
Avatar billede arne_v Ekspert
13. december 2008 - 05:16 #29
using System;
using System.Collections.Generic;
using System.Threading;
using System.Net.Mail;
using System.Drawing;
using System.Windows.Forms;

namespace E
{
    public partial class MainForm : Form
    {
        private Queue<MailJob> q;
        public MainForm(Queue<MailJob> q)
        {
            InitializeComponent();
            this.q = q;
            progressBar1.Minimum = 0;
            progressBar1.Maximum = q.Count;
            progressBar1.Step = 1;
        }
        public void Button1Click(object sender, EventArgs e)
        {
            Thread[] t = new Thread[20];
            for(int i = 0; i < t.Length; i++)
            {
                t[i] = new Thread(new ThreadStart(SendMails));
                t[i].Start();
            }
        }
        public void SendMails()
        {
            if (progressBar1.InvokeRequired)
            {
                progressBar1.Invoke((MethodInvoker)delegate() { progressBar1.Value = 0; label1.Text = "Running"; });
            }
            else
            {
                progressBar1.Value = 0;
                label1.Text = "Running";
            }
            bool done = false;
            do
            {
                MailJob mj = null;
                lock(q)
                {
                    if(q.Count > 0) {
                        mj = q.Dequeue();
                    }
                }
                if(mj != null)
                {
                    SendMail(mj);
                    lock(progressBar1)
                    {
                        if (progressBar1.InvokeRequired)
                        {
                            progressBar1.Invoke((MethodInvoker)delegate() { progressBar1.Value++; if(progressBar1.Value == progressBar1.Maximum) label1.Text = "Done"; });
                        }
                        else
                        {
                            progressBar1.Value++;
                            if(progressBar1.Value == progressBar1.Maximum) label1.Text = "Done";
                        }
                    }
                }
                else
                {
                    done = true;
                }
            }
            while(!done);
        }
        public void SendMail(MailJob mj)
        {
            SmtpClient srv = new SmtpClient("arne");
            MailMessage msg = new MailMessage();
            msg.From = new MailAddress("arne@arne");
            msg.To.Add(new MailAddress(mj.To));
            msg.Subject = mj.Subject;
            msg.Body = mj.Body;
            srv.Send(msg);
        }
    }
}
Avatar billede arne_v Ekspert
13. december 2008 - 05:16 #30
using System.Windows.Forms;
using System.Drawing;

namespace E
{
    public partial class MainForm
    {
        private ProgressBar progressBar1;
        private Button button1;
        private Label label1;
        private void InitializeComponent()
        {
            progressBar1 = new ProgressBar();
            button1 = new Button();
            label1 = new Label();
            SuspendLayout();
            progressBar1.Location = new Point(50, 50);
            progressBar1.Name = "progressBar1";
            progressBar1.Size = new Size(200, 25);
            button1.Location = new Point(50, 100);
            button1.Size = new Size(75, 40);
            button1.Text = "Send email";
            button1.Click += new System.EventHandler(Button1Click);
            label1.Location = new Point(150, 100);
            label1.Size = new Size(125, 40);
            label1.Font = new Font(FontFamily.GenericSerif, 24.0f);
            label1.Text = "";
            ClientSize = new Size(300, 200);
            Controls.Add(progressBar1);
            Controls.Add(button1);
            Controls.Add(label1);
            Text = "Mail sender";
            ResumeLayout(false);
        }
    }
}
Avatar billede pablopablo Nybegynder
13. december 2008 - 09:56 #31
Du er for vild Arne! Jeg kigger lige helt i dybden på det i løbet af i morgen, så vender jeg lige tilbage!

På forhånd tak!
Avatar billede arne_v Ekspert
19. januar 2009 - 02:19 #32
Det er vist blevet imorgen.

Jeg smider et svar.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester