0

I'm trying to send emails from a .NET application using Outlook Object Model.

My application displays the Outlook message window so the user can see what we're sending and edit it first. When the user hits the Send button, the Outlook window closes, and the message gets sent. This works perfectly as long as the Outlook application is already running.

If the Outlook application isn't already running, the message gets stuck in the Outbox, and will not send until I start Outlook. When I start Outlook, I can see the message sitting in the Outbox folder for a few seconds, then it gets sent. I need to show the New Message form to Outlook user to select the recipient(s) and possibly edit the message before sending.

Note: I know that this question was already asked here Email sent with Outlook Object Model stays in Outbox until I start Outlook and the solution exists, but it is not provided (only the small hint is provided) and unfortunately I cannot ask for clarification / code example because I have not enough "reputation". I tried to write my own implementation of the hint provided, but the SyncEnd event is fired only when Outlook is already open (just to remind, the question is about the case then Outlook is closed). My code below. What is wrong?

using Microsoft.Office.Interop.Outlook;
using OutlookApp = Microsoft.Office.Interop.Outlook.Application;
class Mailer
{
  AutoResetEvent mailSentEvent = new AutoResetEvent(false);

  public void CreateMail()
  {
    OutlookApp outlookApp = null;
    MailItem mailItem = null;
    try
    {
      outlookApp = new OutlookApp();
      mailItem = outlookApp.CreateItem(OlItemType.olMailItem);

      mailItem.Subject = "Test Message";
      mailItem.Body = "This is the message.";
      string reportPath = @"C:\temp\aaaaa.pdf";
      mailItem.Attachments.Add(reportPath);
      mailItem.Display(true);

      StartSync(outlookApp);
      bool result = mailSentEvent.WaitOne();
     }
    catch (System.Exception)
    {
        throw;
    }
    finally
    {
      if (mailItem != null) Marshal.ReleaseComObject(mailItem);
      if (outlookApp != null) Marshal.ReleaseComObject(outlookApp);
    }
  }

  private static SyncObject _syncObject = null;

  private void StartSync(OutlookApp outlookApp)
  {
    var nameSpace = outlookApp.GetNamespace("MAPI");
    _syncObject = nameSpace.SyncObjects[1];
    _syncObject.SyncEnd += new Microsoft.Office.Interop.Outlook.SyncObjectEvents_SyncEndEventHandler(OnSyncEnd);
    _syncObject.Start();
}

  private void OnSyncEnd()
  {
    mailSentEvent.Set();
  }
}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Yumb
  • 1
  • 5
  • Where and when do you run the code? Is it a web server or service? – Eugene Astafiev May 31 '18 at 20:19
  • @EugeneAstafiev Thank you for the answer. It is neither web server nor service (as I understood, it's not possible to use OOM from the service - isn't it correct). I'm calling this class from the desktop application (Crystal Reports viewer) and want to send report through Outlook mail. – Yumb Jun 03 '18 at 08:08
  • Try to get an instance of the `Explorer` class and hold that reference until you are done. – Eugene Astafiev Jun 03 '18 at 08:11
  • @EugeneAstafiev 1.Explorer or Inspector (as it was recommended in another post)? Can you please provide or refer the example? 2."Try to get an instance of the Explorer class and hold that reference" - should it be to create a (static?) class variable and assign it? Thank you again! – Yumb Jun 03 '18 at 08:40

1 Answers1

0

the SyncEnd event is fired only when Outlook is already open

That is not true. The SyncObjects collection contains all Send\Receive groups. You need to iterate over all objects in the collection and call the Start method, for example:

  Set sycs = nsp.SyncObjects 
  For i = 1 To sycs.Count 
    Set syc = sycs.Item(i) 
    strPrompt = MsgBox("Do you wish to synchronize " &; syc.Name &;"?", vbYesNo) 
    If strPrompt = vbYes Then 
      syc.Start 
    End If 
  Next 
Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
  • Thank you for the answer. 1.I feel this behavior as SyncEnd event is fired only when Outlook is already open. If I set the breakpoint inside the OnSyncEnd event handler (see my code above), the flow stops on it only if Outlook was previously open. If it was closed, after clicking Send button on the New Mail window, the window is closed and I can wait for a while but OnSyncEnd event handler is not called. 2.If I start multiple Sync Objects (all that I find), How can I catch the SyncEnd event? Attach same handler to each of them? Thanks! – Yumb Jun 03 '18 at 08:15
  • Yes, you need to attach an event handler to each SyncObject instance. – Eugene Astafiev Jun 03 '18 at 08:19