0

I wrote a class to send emails via outlook automated. Everything is fine beside the small case, that the mail is generated, put to the "outgoing" folder and then outlook is closed. The closing is so fast, that the mail is sended once I start outlook the next time.

Here is my code:

public class MyMail
{
    private const double WaitingForSending = 30.0;

    #region Local variables
    public bool SSL_Encryption = true;
    public System.Collections.Generic.List<System.Net.Mail.MailAddress> Address = null;
    public System.Collections.Generic.List<System.Net.Mail.MailAddress> CC = null;
    public System.Collections.Generic.List<System.Net.Mail.MailAddress> BCC = null;
    public System.Collections.Generic.List<string> AttachmentFileName = null;
    public string Body = "";
    public string Subject = "";
    #endregion


    public void SendMail()
    {
        double Waited = .0;
        string fAddress = string.Empty;

        if (this.Address == null) { return; }
        Microsoft.Office.Interop.Outlook.Application OL = new Microsoft.Office.Interop.Outlook.Application();

        Microsoft.Office.Interop.Outlook.MailItem Mail = (Microsoft.Office.Interop.Outlook.MailItem)OL.CreateItem(OlItemType.olMailItem);
        Mail.Subject = this.Subject;
        if (this.Address != null) { foreach (System.Net.Mail.MailAddress MA in this.Address) { fAddress += MA.Address + "; "; } Mail.To = fAddress; fAddress = string.Empty; }
        if (this.CC != null) { foreach (System.Net.Mail.MailAddress MA in this.CC) { fAddress += MA.Address + "; "; } Mail.CC = fAddress; fAddress = string.Empty; }
        if (this.BCC != null) { foreach (System.Net.Mail.MailAddress MA in this.BCC) { fAddress += MA.Address + "; "; } Mail.BCC = fAddress; fAddress = string.Empty; }
        Mail.Body = this.Body;
        if (this.AttachmentFileName != null) { foreach (string Att in this.AttachmentFileName) { if (System.IO.File.Exists(Att)) { Mail.Attachments.Add(Att, Microsoft.Office.Interop.Outlook.OlAttachmentType.olByValue, Type.Missing, Type.Missing); } } }
        Mail.Display(false);

        try
        {
            Mail.Send();
        } catch (System.Exception ex) { throw ex; }

        /*
        while (!Mail.Sent && Waited < WaitingForSending)
        {
            System.Threading.Thread.Sleep(500);
            Waited += 0.5;
        }
        */
    }
}

The "waiting loop", I commented is not working, because outlook is closing in the function Mail.Send().

Does anybody have an idea, how I can let outlook wait until the mail is sent?

Greetings, Jan

Jason Johnston
  • 17,194
  • 2
  • 20
  • 34
Jan021981
  • 521
  • 3
  • 28
  • Do you have to use outlook to send email? – L.B Sep 29 '17 at 23:07
  • Yes, I need to use outlook as it's used as the standard mailing tool in my company... – Jan021981 Sep 29 '17 at 23:11
  • `standard mailing tool` is for people who manually send emails. You are using *codes* to send email. So I don't think it is necessary. See for ex https://stackoverflow.com/questions/9201239/send-e-mail-via-smtp-using-c-sharp – L.B Sep 29 '17 at 23:22
  • I'd like to have this mail in my Outlook "Sent-folder" afterwards... – Jan021981 Sep 29 '17 at 23:24

3 Answers3

0

Outlook will close as soon as the last explorer or inspector closes. To prevent that, either make sure either an explorer or inspector is shown, or at least hold a reference to one of these objects (they don't have to be visible). An inspector can be retrieved from MailItem.GetInspector or MAPIFolder.GetExplorer.

You might also want to use Namespace.SendAndRecive to send the message. Keep in mind that SendAndRecive is asynchronous, so you will need to wait for the SyncObject.SyncEnd event to fire (by then you can safely release explorer or inspector and let Outlook close). SyncObject can be retrieved from the Namespace.SyncObjects collection.

Dmitry Streblechenko
  • 62,942
  • 4
  • 53
  • 78
  • I still know the SendAndRecive function but I want to avoid it, because I need to define a SR Groupe first, so I cannot use this function on every computer in my company OR I have to send and receive all the folders - that can take a very long time in some cases. I think, I'll store the mail ID and restart Microsoft.Outlook, get the mail by the id and wait, until the `sent`flag is true. – Jan021981 Sep 29 '17 at 23:38
0

I now found another solution. Please find a working solution attached:

    public static class MAPIOutlook
{
    public static OL.Application GetOutlook(out bool StillRunning)
    {
        OL.Application OLApp = null;
        OL.NameSpace nameSpace = null;

        if (System.Diagnostics.Process.GetProcessesByName("OUTLOOK").Count() > 0)
        {
            StillRunning = true;
            try
            {
                OLApp = System.Runtime.InteropServices.Marshal.GetActiveObject("Outlook.Application") as Microsoft.Office.Interop.Outlook.Application;
            }
            catch {
                KillOutlook();
                OLApp = new OL.Application();
                nameSpace = OLApp.GetNamespace("MAPI");
                nameSpace.Logon("", "", System.Reflection.Missing.Value, System.Reflection.Missing.Value);
            }
        }
        else
        {
            StillRunning = false;
            OLApp = new OL.Application();
            nameSpace = OLApp.GetNamespace("MAPI");
            nameSpace.Logon("", "", System.Reflection.Missing.Value, System.Reflection.Missing.Value);
        }

        return OLApp;
    }


    public static void KillOutlook()
    {
        foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcessesByName("OUTLOOK")) { p.Kill(); }
    }

    public static void SendMailAdv(string[] To, string[] CC, string[] BCC, string Subject, string Body, string[] Attachment)
    {
        bool StillRunning = false;
        OL.Application OlApp = GetOutlook(out StillRunning);
        OL.NameSpace NS = OlApp.GetNamespace("MAPI");
        OL.MAPIFolder MFold = NS.GetDefaultFolder(OL.OlDefaultFolders.olFolderOutbox);
        OL.MailItem MI = (OL.MailItem)OlApp.CreateItem(OL.OlItemType.olMailItem);
        OL.Recipients oReci = MI.Recipients;

        foreach(string str in To)
        {
            OL.Recipient Rec = MI.Recipients.Add(str);
            Rec.Type = (int)OL.OlMailRecipientType.olTo;
        }

        foreach (string str in CC)
        {
            OL.Recipient Rec = MI.Recipients.Add(str);
            Rec.Type = (int)OL.OlMailRecipientType.olCC;
        }

        foreach (string str in To)
        {
            OL.Recipient Rec = MI.Recipients.Add(str);
            Rec.Type = (int)OL.OlMailRecipientType.olBCC;
        }

        MI.Subject = Subject;
        MI.Body = Body;

        foreach(string str in Attachment)
        {
            if (System.IO.File.Exists(str.Trim()))
            {
                MI.Attachments.Add(str.Trim(), OL.OlAttachmentType.olByValue, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
            }
        }

        int nOutItems = MFold.Items.Count;

        MI.Send();

        while(nOutItems != MFold.Items.Count)
        {
            System.Threading.Thread.Sleep(250);
        }

        if (!StillRunning)
        {
            OlApp.Application.Quit();
            OlApp.Quit();
            KillOutlook();
        }
    }
}
Jan021981
  • 521
  • 3
  • 28
0

First of all, I'd follow Dmitry's suggestions listed there.

Also I have noticed that you show an inspector window before calling the Send method of the MailItem class. That's not required may cause the behavior you see currently. Need to admit that all Outlook objects are declared at the method scope which limits the lifetime to the method.

public class MyMail
{
    private const double WaitingForSending = 30.0;

    #region Local variables
    public bool SSL_Encryption = true;
    public System.Collections.Generic.List<System.Net.Mail.MailAddress> Address = null;
    public System.Collections.Generic.List<System.Net.Mail.MailAddress> CC = null;
    public System.Collections.Generic.List<System.Net.Mail.MailAddress> BCC = null;
    public System.Collections.Generic.List<string> AttachmentFileName = null;
    public string Body = "";
    public string Subject = "";
    #endregion

    private Microsoft.Office.Interop.Outlook.Application OL;
    private Microsoft.Office.Interop.Outlook.MailItem Mail;

    public void SendMail()
    {
        double Waited = .0;
        string fAddress = string.Empty;

        if (this.Address == null) { return; }
        OL = new Microsoft.Office.Interop.Outlook.Application();

        Mail = (Microsoft.Office.Interop.Outlook.MailItem)OL.CreateItem(OlItemType.olMailItem);
        Mail.Subject = this.Subject;
        if (this.Address != null) { foreach (System.Net.Mail.MailAddress MA in this.Address) { fAddress += MA.Address + "; "; } Mail.To = fAddress; fAddress = string.Empty; }
        if (this.CC != null) { foreach (System.Net.Mail.MailAddress MA in this.CC) { fAddress += MA.Address + "; "; } Mail.CC = fAddress; fAddress = string.Empty; }
        if (this.BCC != null) { foreach (System.Net.Mail.MailAddress MA in this.BCC) { fAddress += MA.Address + "; "; } Mail.BCC = fAddress; fAddress = string.Empty; }
        Mail.Body = this.Body;
        if (this.AttachmentFileName != null) { foreach (string Att in this.AttachmentFileName) { if (System.IO.File.Exists(Att)) { Mail.Attachments.Add(Att, Microsoft.Office.Interop.Outlook.OlAttachmentType.olByValue, Type.Missing, Type.Missing); } } }
        // the following method is not required for sending emails
        // Mail.Display(false);

        try
        {
            Mail.Send();
        } catch (System.Exception ex) { throw ex; }           
    }
}

The best way to be sure that a message was sent successfully is to handle the ItemAdd event on the Sent Items folder. The event is fired when one or more items are added to the specified collection.

Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45