COMException in Outlook Online (non-cached) Mode only - c#

The example code shown below illustrates the issue I'm having, namely when I start Outlook in Online mode I cannot get most of the properties of the mail item passed to the OutboxItems_ItemAdd handler. The error returned is:
Attachments = {System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.InteropServices.COMException: Exception from HRESULT: 0x8004010F
--- End of inner exception stack trace ---
at System.Runtime...
I do NOT get this error when attempting to retrieve the properties of the mail item in the SentItems_ItemAdd handler. Also, it is important to note that everything works perfectly when in Outlook cached mode; the issue in the Outbox handler is only when Outlook starts in Online mode. Is this a bug, or am I just doing something wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
namespace OnlineErrorTest{
public partial class ThisAddIn{
Outlook.Folder sentFolder;
Outlook.Folder outboxFolder;
Outlook.Items sentItems;
Outlook.Items outboxItems;
private void ThisAddIn_Startup(object sender, System.EventArgs e) {
sentFolder = this.Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail) as Outlook.Folder;
outboxFolder = this.Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderOutbox) as Outlook.Folder;
sentItems = sentFolder.Items;
outboxItems = outboxFolder.Items;
sentItems.ItemAdd += SentItems_ItemAdd;
outboxItems.ItemAdd += OutboxItems_ItemAdd;
}
private void OutboxItems_ItemAdd(object Item) {
Outlook.MailItem mi = Item as Outlook.MailItem;
Outlook.Recipients r = mi.Recipients; //CAUSES EXCEPTION //System.Runtime.InteropServices.COMException: Exception from HRESULT: 0x8004010F
}
private void SentItems_ItemAdd(object Item) {
Outlook.MailItem mi = Item as Outlook.MailItem;
Outlook.Recipients r = mi.Recipients; //WORKS FINE
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e) {
}
private void InternalStartup(){
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
}
}

The error code is MAPI_E_NOT_FOUND, which means the item no longer exists - this is hardly surprising: by the time your code gets to it, Exchange Server most likely already sent the message and moved it to the Sent Items folder.
You should never touch the messages being submitted - even if you succeed in doing so, touching an item with OOM aborts the submission process. Use Application.ItemSend event instead - it is your last chance to access the item before it is handed over to the spooler and sent.

Related

Creating an On-send prompt in Outlook with VSTO and in C#

I have a requirement to intercept the sending of a new email. All I want to do initially is ask the user "Are you sure you want to send?" and then to either proceed with the sending or cancel it depending on their response.
I found this code snippet which looks perfect for my needs but couldn't get it to work in a Win Forms test application either in VB.Net or after trying to convert it to C#. It then occurred to me that the code may only work in a VSTO Add-in (Is this correct?).
So I then used this Walkthrough to create a VSTO Add-in in C# and made sure that it worked as described, which it does (it pumps some text into the Subject and Body of a new message).
I have tried to add the first example which is in VB.Net into the working C# example but I'm a novice and don't know enough about VSTO or C# to see where I'm going wrong.
The code compiles without errors but when run, Outlook takes a long time loading the Add-in and displays a dialogue stating:
An add-in could not be found or loaded
and then:
Could not create an instance of startup object
PromptToFile_Plug_in.ThisAddIn in assembly PromptToFile Plug-in,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
Where am I going wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Diagnostics;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
using System.Windows.Forms;
namespace PromptToFile_Plug_in
{
public partial class ThisAddIn
{
Outlook.Inspectors inspectors;
Outlook.Application myOlApp = new Outlook.Application();
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
inspectors = this.Application.Inspectors;
inspectors.NewInspector +=
new Microsoft.Office.Interop.Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
// Note: Outlook no longer raises this event. If you have code that
// must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
}
void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
Outlook.MailItem mailItem = Inspector.CurrentItem as Outlook.MailItem;
if (mailItem != null)
{
if (mailItem.EntryID == null)
{
mailItem.Subject = "This text was added by using code";
mailItem.Body = "This text was added by using code";
}
}
}
private void Initialize_handler()
{
myOlApp = this.Application;
}
private void myOlApp_ItemSend(object Item, bool Cancel)
{
string prompt;
// prompt = "Are you sure you want to send " + Item.Subject + "?";
prompt = "Are you sure you want to send?";
MessageBox.Show(prompt, "Prompt to File", MessageBoxButtons.OKCancel);
//if (MessageBox.(prompt, Constants.vbYesNo + Constants.vbQuestion, "Sample") == Constants.vbNo)
// Cancel = true;
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
First of all, there is no need to create a new Outlook Application instance in the add-in class:
Outlook.Application myOlApp = new Outlook.Application();
Instead, use the Application property available in your add-in class.
Second, there is no need to keep the following method because it will never be called:
private void Initialize_handler()
{
myOlApp = this.Application;
}
Unlike VBA, you can't subscribe to the events just declaring the source objects with keywords. Instead, you need to subscribe to the events in the code like you did for the NewInspector event. For example, the following code can be used for handling the ItemSend event in VSTO add-ins:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
this.Application.ItemSend += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);
}
void Application_ItemSend(object Item, ref bool Cancel)
{
if (Item is Outlook.MailItem)
{
Outlook.MailItem mail = (Outlook.MailItem)Item;
// your code goes here
}
}
Finally, pay attention to the ref attribute for the Cancel parameter in the event handler signature.

How do I create an Outlook add-in that alerts the user when they attempt to reply to senders that are outside of their domain?

I am new to coding in c#. I am currently trying to create an Outlook add-in to prompt and alert users if they are to attempt to reply to anyone that is not from "#abc.com". For example if 'ben#abc.com' is to trying to reply to 'jack#def.com', a window to alert Ben will be prompted warning him "You are about to reply to someone that is not from '#abc.com'." with the options of 'ok' and 'cancel'.
I referred online for the code below but this add-in only allows me to edit the field values of the email I am trying to send. I am unable to even figure out how to address and implement the code to deal with replying. I have tried researching online and have seen methods like .reply() but I am confused as to how to apply them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
namespace FirstOutlookAddIn
{
public partial class ThisAddIn
{
Outlook.Inspectors inspectors;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
inspectors = this.Application.Inspectors;
inspectors.NewInspector +=
new Microsoft.Office.Interop.Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
}
void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
Outlook.MailItem mailItem = Inspector.CurrentItem as Outlook.MailItem;
if (mailItem != null)
{
if (mailItem.EntryID == null)
{
mailItem.To = "Testing for Recipient.";
mailItem.Subject = "Currently testing add-in for Subject.";
mailItem.Body = "Currently testing add-in for Body.";
mailItem.CC = "Testing for CC.";
}
}
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
// Note: Outlook no longer raises this event. If you have code that
// must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
Firstly, you are only tracking Inspectors.NewInspector event. But in most cases replies will be inline - you also need Explorer.InlineResponse event (where Explorer comes from Application.ActiveExplorer, which can be null on startup, so you'd also need Application.Explorers.NewExplorer event).
Secondly, you will need to loop through all recipients in the mailItem.Recipients collection, and for each Recipient, check the Recipient.Address property (which you can test for the match).
Listen to send event, as it will be triggered irrespective of inline replies or inspector level replies.
this.Application.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);
then implementation of this can be done as below,
/// param : item -> mail item to be sent
/// param : cancel -> allows you to cancel sending mail in outlook. By default value is false.
private void Application_ItemSend(object item, ref bool cancel){
Outlook.MailItem mail = (Outlook.MailItem)item;
// read "mail.To" and check for your logic;
// if To list has other domains, then show the warning prompt maybe like below,
var result = MessageBox.Show("yourmessage","title",MessageBoxButtons.YesNo);
if(result == DialogResult.No)
cancel = true; // setting this to `true` will stop sending an email out.
}
you can read on this event in MS blog here Item_Send

C# VSTO Outlook error "An object could not be found"

I am working on an Outlook AddIn with a custom ribbon. The user opens a mail item in Read mode and clicks a button on the ribbon and the program will move the email to a folder (not the user's personal mailbox, but rather to a different mailbox that user has access to).
When the program is run, it works the first time, but the second time the user runs it, it throws an error:
"The attempted operation failed. An object could not be found."
Here is the relevant code:
(in ThisAddIn.cs)
public partial class ThisAddIn
{
public Outlook.Application OutlookApplication;
void ThisAddIn_Startup(object sender, System.EventArgs e)
{
OutlookApplication = this.Application;
}
(etc)
(In Ribbon1.cs, in a method that gets called upon button_Click)
Outlook.Inspector inspector = Globals.ThisAddIn.OutlookApplication.ActiveInspector();
Outlook.MailItem item = inspector.CurrentItem as Outlook.MailItem;
Outlook.Stores stores = null;
Outlook.Folder destinationMailboxFolderInbox = null;
and
try
{
// Set the mailbox move location
stores = Globals.ThisAddIn.OutlookApplication.GetNamespace("MAPI").Stores;
foreach (Outlook.Store store in stores)
{
attachmentsFoundTotal++;
if (store.DisplayName == destinationMailbox)
{
destinationMailboxFolderInbox = (Outlook.Folder)store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
try
{
// the code breaks on this line below:
item.Move(destinationMailboxFolderInbox.Folders[destinationMailboxFolder]);
}
catch (Exception ex3)
{
System.Windows.Forms.MessageBox.Show(ex3.Message + " Could not find Outlook folder " + destinationMailboxFolder + ". The mail item was not moved." );
}
}
}
}
catch (Exception ex2)
{
System.Windows.Forms.MessageBox.Show(ex2.Message);
}
UPDATE: After trial & error testing, the only way I could resolve the Outlook 2010 bug was to have the Outlook view switch to the folder where the mail item was moved, using this command after the command to move the item to myfolder.
Globals.ThisAddIn.OutlookApplication.ActiveExplorer().CurrentFolder = myFolder;
When the program is run, it works the first time, but the second time the user runs it, it throws an error:
The Outlook UI is not refreshed when an item is moved to another place. You need to refresh the view on your own to get a live reference. Any UI objects still hold an old reference.
For example, the Move method moves a Microsoft Outlook item to a new folder and returns an Object value that represents the item which has been moved to the designated folder.

Getting "cannot assign to 'reply' because method group when adding event in outlook add-in

Using VSTO 2012 with Outlook 2010 PIA (i.e. version 12), I'm attempting to hook the reply event on a message; but getting a compile error that I am assigning to a method group. I've seen some other code around the web that uses the casting method below, but it won't compile for me. The definitiion in the type lib appears to lack the "event" keyword which may be the problem, but not clear to me how to solve.
using Outlook = Microsoft.Office.Interop.Outlook;
...
void Application_ItemLoad(object Item)
{
if (Item is Outlook.MailItem)
{
Outlook.MailItem mi = Item as Outlook.MailItem;
Outlook.MailItemClass emi = Item as Outlook.MailItemClass;
emi +=new Microsoft.Office.Interop.Outlook.ItemEvents_10_ReplyEventHandler(MyReply);
}
}
private void MyReply(object Response, ref bool Cancel)
{
if (Response is Outlook.MailItem)
{
Outlook.MailItem re = Response as Outlook.MailItem;
//..
}
}
sugestions and help appreciated. Thanks!
This is the problem:
emi +=new Microsoft.Office.Interop.Outlook.ItemEvents_10_ReplyEventHandler(MyReply);
Currently you're trying to add an event to the object itself - not to a specific event. You want the ItemEvents_Event_Reply event (I suspect) in which case you need:
emiItemEvents_Event_Reply += MyReply;
(Using a simple method group conversion instead of explicitly creating a new handler. Even if you do want to use the new ...(MyReply) syntax, a few choice using directives would make your code more readable.)
EDIT: Okay, you can use the MailItem.Reply event instead:
void Application_ItemLoad(object item)
{
var mailItem = item as Outlook.MailItem;
if (mailItem != null)
{
mailItem.Reply += MyReply;
}
}

Tracking eMails in Outlook 2007

Greetings Overflowers,
I am trying to develop a VSTO/C# corporate email tracker for specially signed emails.
I am relying on:
Inspectors.NewInspector
Inspector.Close
Inspector.Activate
Inspector.Deactivate
Somehow, the Inspector events stop firing after sometime.
I register 2, 3 and 4 in the body of 1 after checking for the sign.
I tried to keep track of already registered inspectors but no hope.
Any clue ?
UPDATE: Here is a sample code. The evens OnSelect and OnOpen fires few times and then stops suddenly:
using System;
using System.Collections;
using Microsoft.Office.Interop.Outlook;
// using Microsoft.Office.Core;
namespace eMailTrackingSystem
{
public enum TrackingEvent
{
Opened, Closed, Forwarded, Deleted
}
public partial class eMTSAddIn
{
private ArrayList trackedEmails = new ArrayList();
private void InternalStartup()
{
this.Application.ActiveExplorer().SelectionChange += new ExplorerEvents_10_SelectionChangeEventHandler(OnSelect);
}
private void OnSelect()
{
Selection selection = this.Application.ActiveExplorer().Selection;
foreach (object item in selection)
{
if (item is MailItem)
{
MailItem email = (MailItem)item;
if (email.Subject == "eMTS" && !trackedEmails.Contains(email.EntryID))
{
email.Open += new ItemEvents_10_OpenEventHandler(OnOpen);
trackedEmails.Add(email.EntryID);
}
}
}
}
private void OnOpen(ref bool cancel)
{
}
private void OnClose()
{
}
}
}
Regards
Are you using Inspector Wrappers? They are essential for properly dealing with every item that is opened by a user:
Developing an Inspector Wrapper for Outlook 2010:
http://msdn.microsoft.com/en-us/library/ff973716.aspx
A similar approach can be used for monitoring the items a user has selected in the Explorer.

Categories