0

I want to send an E-Mail to multiple customers with Outlook. For this I have a method in my Program that iterates the recipients, composes the message body and displays the first message as a Preview.

This is a simplified version of that method:

public void CreateMails(List<InfoMailRecipient> recipients)
{
    Microsoft.Office.Interop.Outlook.Application outlook = new Microsoft.Office.Interop.Outlook.Application();
    foreach (InfoMailRecipient recipient in recipients)
    {
        MailItem mail = outlook.CreateItem(OlItemType.olMailItem);
        mail.SentOnBehalfOfName = "Sending User";
        mail.BCC = recipient.EMailAddress;

        mail.Subject = "TEST";
        mail.BodyFormat = OlBodyFormat.olFormatHTML;
        mail.HTMLBody = "<html><body>test</body></html>";
        mail.Display(true);
    }
}

When the Outlook message window is displayed, no matter if I just close the window or click "Send", as soon as the next MailItemshould be created I get an exception "RPC Server unavailable". Obviously because Outlook has closed. I've found out that when I remove the line

mail.Display(true);

and just call .Send(); all the messages are sent properly. But then Outlook stays open. Even if I call .Quit() after the foreach loop.

How do I handle this Outlook instance properly?

Update 1 - Manual GC-Call

public void CreateMails(List<InfoMailRecipient> recipients)
{
    Microsoft.Office.Interop.Outlook.Application outlook = new Microsoft.Office.Interop.Outlook.Application();
    foreach (InfoMailRecipient recipient in recipients)
    {
        MailItem mail = outlook.CreateItem(OlItemType.olMailItem);
        mail.SentOnBehalfOfName = "Sending User";
        mail.BCC = recipient.EMailAddress;

        mail.Subject = "TEST";
        mail.BodyFormat = OlBodyFormat.olFormatHTML;
        mail.HTMLBody = "<html><body>test</body></html>";
        mail.Send();
    }
    outlook.Quit();
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

Outlook keeps running.

Marco Rebsamen
  • 605
  • 7
  • 30

1 Answers1

0

This appears to work - can you let us know if it works for you too?

    public static void Main(string[] args)
    {
        CreateMails(new List<string>() {"emailaddresshere"});
        Console.WriteLine("finished");
        Console.ReadLine();
    }

    public static void CreateMails(List<string> recipients)
    {
        Microsoft.Office.Interop.Outlook.Application outlook = new Microsoft.Office.Interop.Outlook.Application();
        foreach (string recipient in recipients)
        {
            MailItem mail = outlook.CreateItem(OlItemType.olMailItem);
            mail.SentOnBehalfOfName = "Sending User";
            mail.BCC = recipient;

            mail.Subject = "TEST";
            mail.BodyFormat = OlBodyFormat.olFormatPlain;
            mail.HTMLBody = "Hello";
            mail.Send();
            System.Runtime.InteropServices.Marshal.ReleaseComObject(mail); // key change
        }
        GC.Collect();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        outlook.Application.Quit();
        outlook.Quit();
        System.Runtime.InteropServices.Marshal.ReleaseComObject(outlook); // key change
        outlook = null;
        GC.Collect();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

Also have a read of https://ausdotnet.wordpress.com/category/technical/com-interop/ and How to close outlook after automating it in c# .

mjwills
  • 23,389
  • 6
  • 40
  • 63
  • It does! Thank you. It seems to work already with `outlook.Quit(); Marshal.ReleaseComObject(outlook);` – Marco Rebsamen Jun 08 '17 at 09:43
  • That is awesome news! – mjwills Jun 08 '17 at 09:44
  • Sometimes it does, sometimes it doesn't.... I ended up releasing the object and kill the process... never mind... – Marco Rebsamen Jun 08 '17 at 14:28
  • Show me the final code you used (at https://dotnetfiddle.net/) and I can check if you missed something... – mjwills Jun 08 '17 at 21:56
  • Since it was still working nicely in the testing app I digged deeper into this and I think I've tricked my self with this simplified version. Because in the actual method I'm additionally creating a attachment. And I guess that object was still referencing outlook. I now release that object too and for now it seems to run even after multiple tests. – Marco Rebsamen Jun 09 '17 at 09:20
  • Yep - it is super important that you ReleaseComObject absolutely everything. – mjwills Jun 09 '17 at 12:59