Prevent MailItem.Reply from opening Inspector window in Outlook 2010? - c#

I am building a shared-addin for Outlook.
Inside the code, I am creating a reply email using MailItem.Reply() method
and discarding it later. I am using this to get the sender email address
for emails coming through Exchange server.
It was working fine for Outlook 2007.
But for Outlook 2010, the Reply method seems to opening the mail editor window.
I am on windows 7.
Is there any way to suppress that window or write seperate code based on Outlook version?

If you plan on discarding the message - don't create it to begin with (don't use Reply() unless you intend on sending the message). You can use the Recipient class to resolve an Exchange users email address with minimal resource utilization.
string senderEmail = string.Empty;
Outlook.Recipient recipient = mailItem.Application.Session.CreateRecipient(mailItem.SenderEmailAddress);
if (recipient != null && recipient.Resolve() && recipient.AddressEntry != null)
{
Outlook.ExchangeUser exUser = recipient.AddressEntry.GetExchangeUser();
if (exUser != null && !string.IsNullOrEmpty(exUser.PrimarySmtpAddress))
senderEmail = exUser.PrimarySmtpAddress;
}

Related

Adding to Outlook Email Recipient using VSTO before sending email

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

VSTO Outlook Addin: wired Item object in Application_ItemSend arguments

I wrote a simple VSTO addin for Outlook 2016(part of office 365) to check if there is some email addresses outside our company are mixed in the recipients list.
I simplified the code like below:
int countExternalAddress;
string externalAddresses;
string internalDomain=“#example.com”;
//indicates the email domain of our company, we use exchange server.
private void Application_ItemSend(object Item, ref bool Cancel)
{
countExternalAddress = 0;
externalAddresses="";
Outlook.MailItem item = (Outlook.MailItem)Item;
foreach (Outlook.Recipient recp in item.Recipients)
{
ConvertExchangeAddrToSMTPAddr(recp.AddressEntry.Address);
//by access ExchangeUser.PrimarySmtpAddress
CheckTheAddress(recp.AddressEntry.Address);
}
if (countExternalAddress > 0)
{
Warn();
}
}
The code works with no problem most of time, but some times Warn() function shows warnings based on (part of) the recipients of the LAST email, not the CURRENT one.
The problem cannot be reproduced all the time, but when it occurs, the procedure is like:
Send an email to internal recipients(my colleagues, exchange addresses), the exchange addresses are successfully converted to SMTP address, because they are predefined as "internal" address, the mail will be sent without warning.
send another email to some other internal recipients, the program shows warning of "external address mixed", and the "external" address are from the previously sent email(mentioned in 1 above, not all addresses just one of them), and, the detected external address is in Exchange address format which is supposed to be converted to SMTP format.
Strangely, I cannot find the address in the recipients list of the current email.
If I save the current email and restart outlook, when I pick the saved email and try to resend it, no such "external" address will be detected again.
It looks like the Item object passed by ItemSend event contains some recipient(s) not only belong to the current email but also from the previously sent one, but they are not visible in the current email, moreover I cannot find such recipients in the sent email as well.
The work PC I am using doesn't have debug environment so I am running out of means. Please give me your helps, thanks in advance.
Could it have anything to do with you doing >
if (countExternalAddress > 0)
{
Warn();
}
and not ==
if (countExternalAddress == 0)
{
Warn();
}
Seems odd but it would leave one more email to warn you about.

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.

Send Message with Custom Properties with Redemption

I’m using Redemption.dll to set custom properties to my messages with set_Filed() and get_field() in C#. Everything works perfectly until the moment I send my messages.
From Outlook I use RDOMail.Send() and this sent the message to the Drafts folder. Then I read in the Redemption FAQ that I should use the IMessage::Submit() method (that I couldn’t find anywhere in the dll for .NET) and then use DeliverNow(), method that I did use but to my surprise when I receive my messages I lose the properties I had set.
This is really completely critical to our project since if Outlook can’t send mails it’s worth nothing.
Here is part of my code.
private void adxOutlookEvents_ItemSend(object sender, AddinExpress.MSO.ADXOlItemSendEventArgs e)
{
try
{
RDOSessionClass _RDOSession= MessagesActions.GetRDOSession();
Outlook.MailItem _MailItem= e.Item as Outlook.MailItem;
RDOMail _RdoMail = MessagesActions.GetRDOMail(_RDOSession, _MailItem);
_RdoMail.Send(); // Send using Redeption
e.Cancel = true; // Only send using Redeption
if (_RdoMail != null && Marshal.IsComObject(_RdoMail))
Marshal.ReleaseComObject(_RdoMail);
Redemption.MAPIUtils _MAPIUtils = new MAPIUtils();
_MAPIUtils.DeliverNow(0, 0);
if (_MAPIUtils != null && Marshal.IsComObject(_MAPIUtils))
Marshal.ReleaseComObject(_MAPIUtils);
CurrentInspector.Close(Outlook.OlInspectorClose.olDiscard);
}
catch
{
}
}
Thanks.
When a message is sent through SMTP (unlike between 2 Exchange mailboxes in the same domain), the message is converted to MIME, and all MAPI specific properties are lost.
You can force Outlook to send the message in the TNEF (the infamous winmail.dat) format if yo uset a special named property called UseTnef:
RDOMail.Fields["http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/8582000B"] = true;

Outlook Addin accessing exchange recipient in offline mode?

I'm creating an Outlook addin using VS 2008 and C#. In order to function this addin goes through all the e-mail using Redemption and parses it.
I've recently run into the issue of somebody opening outlook without a network connection (network offline, unplugged, or it's mobile like a laptop and happens to not have connectivity at the moment). It seems to be in getting a list of the recipients.
System.Runtime.InteropServices.COMException (0x80040115): Error in IAddrBook::OpenEntry: MAPI_E_NETWORK_ERROR
Error: The connection to Microsoft Exchange is unavailable. Your network adapter does not have a default gateway.
Component: Microsoft Exchange Address Book
at Redemption.RDOAddressEntryClass.get_SMTPAddress()
This is happening within this code:
/// <summary>
/// Retrieves a list of recipient addresses from an RDOMail object
/// </summary>
/// <param name="rdoItem">The email to analyze</param>
/// <returns>A list of e-mail addresses</returns>
protected List<string> GetRecipients(RDOMail rdoItem)
{
RDORecipients recipients = rdoItem.Recipients;
List<string> recipientList = new List<string>();
if (recipients != null && recipients.Count > 0)
{
for (int i = 1; i <= recipients.Count; i++)
{
RDOAddressEntry addressEntry = recipients[i].AddressEntry;
if (addressEntry != null)
{
string recipient = addressEntry.SMTPAddress;
recipient = recipient.Trim();
if (recipient != null && recipient != String.Empty)
{
recipientList.Add(recipient);
}
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(addressEntry);
addressEntry = null;
}
}
}
if (recipients != null)
{
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(recipients);
recipients = null;
}
return recipientList;
}
So the question is, how do I get the recipients of an e-mail without needing to authenticate to or resolve from Exchange and it dying because there's no network connection?
EDIT: Alternatively - is there a way to cache the smtp e-mail addresses within outlook so that if it later goes offline it doesn't have to resolve the e-mail addresses?
I believe some store providers are wrappers around underlying PST stores. Therefore when accessing certain properties the provider will attempt to sync with the remote server. You should be able to stop this by unwrapping the store from the provider.
Note: that adding an item to an unwrapped store shouldn't persist that change to the server (in the case of IMAP4) for example.
Read more about the UnwrapStore property here at the Redemption website
In most cases PR_SMTP_ADDRESS property should be available in the recipient table (which is stored on the message itself rather than in GAL). You can access that property using RDORecipient.Fields[] - there is no reason to use RDORecipient.AddressEntry (which causes Redemption to call IAddrbook::OpenEntry, and the call can fail in the offline mode).
Look at the recipient table with OutlookSpy (I am its author) - click IMessage, go to the GetRecipientTable tab to make sure the PR_SMTP_ADDRESS property is present.

Categories