2

My C# application lets the user select a file to email. They need to select a recipient from their outlook/exchange contacts because we manage/sync a contact list for the company.

After they send I need to capture the msg file and save it somewhere using the recipient information.

The recipient information isn't available during send so I found some code to use the sent folder ItemAdded event.

This all worked perfectly until someone ran it without outlook already opened in which case that event is never fired. Application.ItemSend(), Inspector.Close() etc. all fire, but not the one I need to get the recipient info.

Anyone have any ideas on why this is not working?

Note: There are several questions about a similar problem where they let the Items variable go out of scope. I am actually returning this and waiting for it to be executed which worked fine when Outlook is opened and eventually the event fires.

This is my method, Outlook is just an alias for Microsoft.Office.Interop.Outlook.

public Outlook.Items Send(string subject, string body) {
    try {
        // Create the Outlook application.
        Outlook.Application oApp = new Outlook.Application();
        Outlook.MAPIFolder sentFolder = oApp.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
        Outlook.Items itmsSentFolder = sentFolder.Items;
        itmsSentFolder.ItemAdd += new Outlook.ItemsEvents_ItemAddEventHandler(Items_ItemAdd);
        Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
        _inspector = oMsg.GetInspector;
        oMsg.Subject = subject;
        oMsg.Body = body;
        int iAttachType = (int)Outlook.OlAttachmentType.olByValue;
        foreach (string file in _attachments) {
            Outlook.Attachment oAttach = oMsg.Attachments.Add(file, iAttachType, 1, Path.GetFileName(file));
        }

        ((Outlook.InspectorEvents_10_Event)_inspector).Close += new Outlook.InspectorEvents_10_CloseEventHandler(Inspector_Close);
        oMsg.Mileage = MESSAGE_FLAG;
        oMsg.Display(false);
        oMsg = null;
        oApp = null;

        return itmsSentFolder;
    } catch (Exception ex) {
        _log.Error("Error sending attachments to Outlook", ex);
        throw;
    }
}

Updated:

public Outlook.Items Send(string subject, string body) {

try {
    _sent = false;
    try {
        _oApp = (Outlook.Application)Marshal.GetActiveObject("Outlook.Application");
        _closeOutlook = false;
    } catch {
        _oApp = new Outlook.Application();
        _closeOutlook = true;
    }
    if (_oApp.Explorers.Count <= 0) {
        _oApp.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).Display();
        _oApp.ActiveExplorer().WindowState = Outlook.OlWindowState.olMinimized;
    }
    _sentFolder = _oApp.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
    _itmsSentFolder = _sentFolder.Items;
    _itmsSentFolder.ItemAdd += new Outlook.ItemsEvents_ItemAddEventHandler(Items_ItemAdd);
    _oMsg = (Outlook.MailItem)_oApp.CreateItem(Outlook.OlItemType.olMailItem);
    _inspector = _oMsg.GetInspector;
    _oMsg.Subject = subject;
    _oMsg.Body = body;

    ((Outlook.ItemEvents_10_Event)_oMsg).Send += new Microsoft.Office.Interop.Outlook.ItemEvents_10_SendEventHandler(MailItem_Send);
    ((Outlook.ItemEvents_10_Event)_oMsg).Write += new Microsoft.Office.Interop.Outlook.ItemEvents_10_WriteEventHandler(MailItem_Write);

    int iAttachType = (int)Outlook.OlAttachmentType.olByValue;
    foreach (string file in _attachments) {
        Outlook.Attachment oAttach = _oMsg.Attachments.Add(file, iAttachType, 1, Path.GetFileName(file));
    }

    ((Outlook.InspectorEvents_10_Event)_inspector).Close += new Outlook.InspectorEvents_10_CloseEventHandler(Inspector_Close);
    _oMsg.Mileage = MESSAGE_FLAG;
    _oMsg.Display(true);
} catch (Exception ex) {
    _log.Error("Error sending attachments to Outlook", ex);
    throw;
}
return _itmsSentFolder;

}

2 Answers2

0

The source object is swiped by the garbage collector. I.e. the ItemAdd event is not fired because the scope of the source object is limited with the try/catch block. You need to declare the object at the global scope and make sure that it is still alive.

P.S. Be aware, the ItemAdd event is not fired when multiple items (more than 16) are added at the same time. This is a well-know issue in Outlook.

Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
  • I was under the impression that it basically just stored it in a local variable for return [link](http://stackoverflow.com/questions/421797/what-really-happens-in-a-try-return-x-finally-x-null-statement). Either way I usually avoid defining things in the try block so I moved it out of the try and got the same behavior and then moved it global to the class and still got the same behavior. I've even tried to move the application object out in case it getting disposed or something took the sent folder with it. No luck. – ShawnDigital Feb 02 '15 at 19:20
  • I 'may' have a solution but I don't know the reason. Adding the block about displaying the inbox seems to work. However, it currently leaves outlook open even after cleaning up my objects created here. P.S. I'm essentially opening a full outlook instance minimized instead of the "automated" usage. – ShawnDigital Feb 02 '15 at 19:57
0

Added Update to my original post with solution. This may be an issue with Outlook 2013 as I found an older product that does something similar and it now hangs when it should be waiting on a ItemAdded event too.

NOTE: You have to clean up all the references afterwards, and that includes knowing if you need to close Outlook when done. Calling oApp.Quit() will quit Outlook even if it was already opened.