Adding to Outlook Email Recipient using VSTO before sending email - c#

Looking a bit of advise or direction in regards to VSTO Ribbons with Outlook in C#.
So far I’ve built an Outlook 2010 Ribbon (using TabMail), this Ribbon opens a WinForms window which allows my users to select contacts from a Custom Built Address Book from a SQL database, via a DataGridView.
The users basically select from a datagridview who they want to email, which then gets added to a toLine list.
Application app = new Microsoft.Office.Interop.Outlook.Application();
Mail item item = app.CreateItem((OlItemType.olMailItem));
item.To = toLine;
Item.Display();
This.close();
The downside of using this approach is the user has to build their To List before they actually compose their email.
I’m now trying to make use of TabMailNewMessage. This should allow the user to compose their email, then click the Ribbon icon within the new message and add to their To List from there.
I’ve got the icon showing okay in the TabMailNewMessage, and I’ve got it to open a 2nd Win Form [currently as a test].
I’m a little unsure how to add to the To List of an already open existing mailItem.
At present all I have on the 2nd Win Form is a button, can someone explain how I can click that button and simply add someone to the To List [of this already composed email]. (I don’t have any code behind the button click as I’m not sure what to do)
I also need to make sure that it doesn’t send the email, but simply adds the user to the To List.
Currently using Office 2010, and VS 2013 (with C#).
Hopefully I’m making some sense here.
Thanks
EDIT:
Not sure if its a simple as
Application app = Globals.ThisAddIn.Application;
MailItem mi = (Outlook.MailItem)app.ActiveInspector().CurrentItem;
Mi.Recipients.Add(“joe#email.com”);
This.Close();

The MailItem.Recipients.Add method allows creating a new recipient in the Recipients collection. The name of the recipient can be a string representing the display name, the alias, or the full SMTP email address of the recipient.
using System.Runtime.InteropServices;
// ...
private bool AddRecipients(Outlook.MailItem mail)
{
bool retValue = false;
Outlook.Recipients recipients = null;
Outlook.Recipient recipientTo = null;
Outlook.Recipient recipientCC = null;
Outlook.Recipient recipientBCC = null;
try
{
recipients = mail.Recipients;
// first, we remove all the recipients of the e-mail
while(recipients.Count != 0)
{
recipients.Remove(1);
}
// now we add new recipietns to the e-mail
recipientTo = recipients.Add("Eugene Astafiev");
recipientTo.Type = (int)Outlook.OlMailRecipientType.olTo;
recipientCC = recipients.Add("Somebody");
recipientCC.Type = (int)Outlook.OlMailRecipientType.olCC;
recipientBCC = recipients.Add("eugene.astafiev#somedomain.com");
recipientBCC.Type = (int)Outlook.OlMailRecipientType.olBCC;
retValue = recipients.ResolveAll();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
finally
{
if (recipientBCC != null) Marshal.ReleaseComObject(recipientBCC);
if (recipientCC != null) Marshal.ReleaseComObject(recipientCC);
if (recipientTo != null) Marshal.ReleaseComObject(recipientTo);
if (recipients != null) Marshal.ReleaseComObject(recipients);
}
return retValue;
}
You may find the following articles helpful:
How To: Fill TO,CC and BCC fields in Outlook programmatically
How To: Create and send an Outlook message programmatically
Also, I'd suggest developing an Outlook form region which can be displayed on the same window instead of using a standalone window, see Create Outlook form regions for more information.

Yes, it is as simple as using Application.ActiveInspector.CurrentItem. But you can do better than that - your ribbon button event handler takes IRibbonControl object as a parameter. Cast the IRibbonControl.Context property to Inspector or Explorer (depending on where the button is hosted).
Also keep in mind that in a COM addin there is no reason to create a new instance of the Outlook.Application object (it will be crippled with the security prompts anyway) - use Globals.ThisAddIn.Application

Related

How can Outlook addin detect when an account is removed

I get accounts from Outlook like below.
Outlook.NameSpace ns = null;
Outlook.Accounts accounts = null;
Outlook.Account account = null;
string accountList = string.Empty;
try
{
ns = OutlookApp.Session;
accounts = ns.Accounts;
for (int i = 1; i <= accounts.Count; i++)
{
account = accounts[i];
accountList += String.Format("{0} - {1}{2}",
account.UserName,
account.SmtpAddress,
Environment.NewLine);
if (account != null)
Marshal.ReleaseComObject(account);
}
MessageBox.Show(accountList);
}
finally
{
if (accounts != null)
Marshal.ReleaseComObject(accounts);
if (ns != null)
Marshal.ReleaseComObject(ns);
}
However, Outlook return accounts, including those that have been removed.
It seems that there are no events that occur when the account is removed.
After the account is removed, is there a way to get the accounts excluding the removed account? How I can get accounts excluding removed account?
On the MAPI level (C++ or Delphi), account events are implemented through IOlkAccountManager::Advise method. You can see the events fire in OutlookSpy (I am its author - click IOlkAccountManager button, go to the Advise tab.
Outlook Object Model does not expose these events. If using Redemption (I am also its author) is an option, it exposes all account events through the RDOAccounts object - AccountChange, AccountAdd, AccountRemove, AccountBeforeRemove, AccountOrderChange.
The Outlook object model doesn't provide any event for that. The best what you can do is to handle the Stores.BeforeStoreRemove event which is fired when a Store is about to be removed from the current session either programmatically or through user action. Here is what MSDN says for the event:
Outlook must be running in order for this event to fire. This event will fire when any of the following occurs:
A store is removed by the user clicking the Close command on the Shortcut menu.
A store is removed programmatically by calling Namespace.RemoveStore.
This event will not fire when any of the following occurs:
When Outlook shuts down and closes a primary or delegate store.
If a store is removed through the Mail applet in the Microsoft Windows Control Panel and Outlook is not running.
A delegate store is removed on the Advanced tab of the Microsoft Exchange Server dialog box.
A store is removed through the Data Files tab of the Account Manager dialog box when Outlook is not running.
An IMAP Store is removed from the profile.
You can use this event to determine that a store has been removed, and take appropriate actions if the store is required for your application (such as remounting the store). Otherwise you would have to resort to polling the Stores collection.

Opening multiple Outlook Window Send Email with C#

I need to open several Outlook windows previously populated with ticulo and email body for later user to inform the senders. I need to open several windows (I walk a grid to know how many windows).
I'm trying to do this with threads but an error message occurs saying: Outlook can not do this because the dialog box is open. Please close it and try again "
How to open multiple competing windows?
Test Call
private void button2_Click(object sender, EventArgs e)
{
int qtdEventos = dgvDescEvento.RowCount;
Thread[] Threads = new Thread[qtdEventos];
try
{
cEmail testeEmail = new cEmail();
for (int i = 0; i < qtdEventos; i++)
{
Threads[i] = new Thread(new ThreadStart(new cEmail().Monta));
}
foreach (Thread t in Threads)
{
t.Start();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace NavEventos.Class
{
class cEmail
{
private Outlook.Application outlookApp;
public cEmail()
{
outlookApp = new Outlook.Application();
}
public void Monta()
{
string pTitulo = "Title";
string pAssunto = "Body test";
Outlook._MailItem oMailItem = (Outlook._MailItem)outlookApp.CreateItem(Outlook.OlItemType.olMailItem);
Outlook.Inspector oInspector = oMailItem.GetInspector;
Outlook.Recipients oRecips = (Outlook.Recipients)oMailItem.Recipients;
#region MONTA ASSUNTO
oMailItem.Subject = pTitulo;
#endregion
#region MONTA CORPO DO E-MAIL
oMailItem.Body = pAssunto;
#endregion
oMailItem.Display(true);
}
}
}
You may not like this... but you shouldn't try. ;(
As you can see the Outlook COM interface is trying very hard to prevent you from doing this, it is one of the limitations of the outlook automation libraries that displaying a mail item is done in a modal kind of way.
There is good reason for this, your user is in your LOB application, then your code wants them to read an email in outlook, which you have done using the COM automation libraries for outlook. Now their outlook icon in the toolbar is flashing because a new email modal window has opened up, but this dialog may have opened up behind your current LOB app.
Now the user will need to switch context into Outlook to see the dialog and read the email.
If you can review your need to open these emails all at the same time then you and outlook com automation will get along just fine :)
Otherwise consider writing a plugin for Outlook and moving your email management routines into outlook itself. In there you can be very creative, sounds like you really need just a master - detail style of interface, like the main outlook browser, so you have a list of these emails and as the user clicks on them they are displayed in the preview inspector.
Maybe the solution is to use your logic to move these messages into a
specific folder in outlook, then use Outlook automation to make this
folder the current active window in outlook, then the user can decide
which emails they want to action or not.

How to access a user property of a custom outlook mail item with Redemption in C#

I’m trying to write a C# application that opens up a outlook custom mail item and fill in multiple user properties. I was able to do so by using the Microsoft Outlook Interop. But I had the annoying security warning each time I tried to change some user property. I found out that Redemption is the perfect tool to avoid this. But when I try to change a user property, Redemption creates a new one instead of using the already existing one.
This is the code I used to change the property with Outlook Interop (Pops up a security warning) :
string customPropertyNamespace = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/";
Outlook._Items oItems = oPublicFolder.Folders["Babillards"].Folders["SYSOTI"].Folders["MEP"].Items;
Outlook._MailItem oMep = oItems.Add("ipm.note.mep");
oMep.PropertyAccessor.SetProperty(customPropertyNamespace + "prop1", "SomeText");
oMep.Display(false);
This all works fine, except for the security warning...
This is the redemption code I'm trying to use :
string customPropertyGUID = "{00020329-0000-0000-C000-000000000046}";
Outlook._Items oItems = oPublicFolder.Folders["Babillards"].Folders["SYSOTI"].Folders["MEP"].Items;
Outlook._MailItem oMep = oItems.Add("ipm.note.mep");
Redemption.SafeMailItem Mep = new Redemption.SafeMailItem();
Mep.Item = oMep;
Mep.set_Fields(Mep.GetIDsFromNames(customPropertyGUID, "prop1"), "SomeText");
oMep.Display(false);
From what I understood this should work. But instead, my mail page opens with all my fields empty. By using OutlookSpy I found out that Redemption creates a new property with this DASL :
http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/prop1/0x0000001F
instead of :
http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/prop1
Can somebody help me? I also tried using the Redemption.MAPIUtils but I ended up with exactly the same result. Is there a way to change a user property by passing the DASL instead of a GUID and ID ?
The two property names are exactly the same - the last part (0x0000001F) is simply property type (= PT_UNICODE). What exactly do you mean by "my mail page opens with all my fields empty"? Do you have a custom form with controls bound to user fields?
Also keep in mind that Outlook might not see all the latest changes made with MAPI until the item is completely dereferenced and reopened. Do o use the data after you restart Outlook and reopen the existing item?
To avoid Outlook caching problem, try to create the message using Redemption, set the property, and only then open the message using Outlook. Somethiong like the following (off the top of my head):
string customPropertyNamespace = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/";
Outlook.Forlder oFolder = oPublicFolder.Folders["Babillards"].Folders["SYSOTI"].Folders["MEP"];
Redemption.RDOSession session = new RDOSesssion();
session.MAPUIOBJECT = Application.Session.MAPIOBJECT;
Redemption.RDOFolder rFolder = session.(RDOFolder)session.GetRDOObjectfromOutlookObject(oFolder);
Redemption.RDOMail rMsg = rFolder.Items.Add("ipm.note.mep");
rMsg.Fields[customPropertyNamespace + "prop1"] = "SomeText";
rMsg.Save();
//reopen in Outlook and display. Or you can use rMsg.Display()
Outlook._MailItem oMep = Application.Session.GetItemFromID(rMsg.EntryID);
oMep.Display(false);

VSTO Outlook User Properties (Custom) not syncing

I have the problem that when i add a custom UserProperty to an Outlook MailItem, it does not get synced to other connected Outlooks.
What can i do to force Outlook to sync the whole email?
My overal problem:
I've got a shared Exchange Mailbox, opened on two clients (in Outlook)
I would like to lock a mail item, if it gets opened in one Outlook and show the second Outlook user a message like "The user XX is currently reading this email"
My way to solve the problem:
Creating a Outlook Plugin.
When user "A" is opening the Email, I am adding a "LockingUser" UserProperty to the MailItem object. If user "B" is trying to open the Email, I am first looking if a "LockingUser" Property exists.
I have disabled the cached mode.
I have tried to update the subject of the email: this works perfectly and gets synced immediatly (but is not a solution for my problem)
private void SetLockingUser(Outlook.MailItem mail)
{
var lockingUserProperty = mail.UserProperties.Find("LockingUser");
if (lockingUserProperty != null)
{
MessageBox.Show("Email locked by: " + lockingUserProperty.Value);
return;
}
var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
var username = identity != null ? identity.Name : "";
lockingUserProperty = mail.UserProperties.Add("LockingUser", Outlook.OlUserPropertyType.olText, false, 1);
lockingUserProperty.Value = username;
mail.Save();
}
Please show the relevant snippet of your code and make sure you call MailItem.Save. Also keep in mind that there will always be lag since the changes will take up to a couple minutes to sync to Exchange and then to another user if cached mode is used. You'd be better off using some external sync mechanism instead of a user property.

How to Program Outlook 2007 Add-In with Multiple Mailboxes

I'm trying to figure how to write a simple add-in for Excel 2007, but one that only interacts with one of my mailboxes. Currently I have two email addresses coming into my outlook, each in a specific 'mailbox'. I was wondering, how would I specify a NewMail event for a specific mailbox?
Or, perhaps not as clean, but how could I write an if function that specifies which mailbox / email any new item is addressed to...
Hopefully this makes sense. Thanks
To catch new mail event, add this code to addin startup method:
this.Application.NewMailEx +=
new Outlook.ApplicationEvents_11_NewMailExEventHandler(Application_NewMailEx);
Then add method to handle NewMailEx event:
void Application_NewMailEx(string EntryID)
{
// get MailItem for this new mail
Outlook.Explorers explorers = this.Application.Explorers;
Outlook.MailItem newMail =
(Outlook.MailItem)explorers.Application.Session.GetItemFromID(EntryID, System.Reflection.Missing.Value);
// check SendUsingAccount to see if it came in mailbox we are interested in
if (newMail.SendUsingAccount.DisplayName == "your.name#your.domain.com")
{
// do whatever You like
}
}
Add using statement also:
using Outlook = Microsoft.Office.Interop.Outlook;

Categories