I have an instance of Microsoft.Office.Interop.Outlook.Application and I add itemSendHandler to the Application.itemSend
Application.itemSend += itemSendHandler
I'm assuming inside the itemSendHandler, the email should already be sent and a Message Id should exist for the email. Yet the following code produces a null messageId:
private void itemSendEventHandler(object sentItem, ref bool Cancel)
}
string PR_INTERNET_MESSAGE_ID_W_TAG = "http://schemas.microsoft.com/mapi/proptag/0x1035001F";
PropertyAccessor propertyAccessor = ((MailItem)sentItem).PropertyAccessor;
// This is null? Why?
string messageId = (string)propertyAccessor.GetProperty(PR_INTERNET_MESSAGE_ID_W_TAG);
ThisAddIn.attemptToReleaseComObject(propertyAccessor);
{
But when I inspect the sent item immediately afterwards, through the code or through a tool (like OutlookSpy or MFCMAPI), the property exists. Why is messageId null during the send event handler?
You need to save the message first before accessing that property. Even then, PR_INTERNET_MESSAGE_ID might not be accessible in the cached mode - Outlook will not synchronize the item in the Sent Items folder with its online replica for the performance reasons, and only the online version of the message will have that property. You can open that message in the online mode using Extended MAPI (C++ or Delphi) or Redemption (any language) by using the MAPI_NO_CACHE flag, but there is no way to do that in OOM.
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.
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;
}
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.
I am writing VSTO Outlook addin in C#, and I need to distinguish, whether given MailItem is incoming or outgoing (or neither, when it is for example a draft).
Is there some foolproof way to do this? Best solution I have now would be getting a list of recipients, cc's, and bcc's, loading email adresses from active accounts, and checking if those two lists intersect, but this seems quite fragile to me, and I hope that there is a better solution.
Use case: I'd like to get a relevant date for an email, which could be either ReceivedTime, or SentOn, but to know which one I should use, I beed to know whether a mail was sent or received.
Thank you for ideas :)
Came to this page because I was having same issue in VBA. Checking the parent folders is cumbersome, as a message can be held either several folders deep (and therefore you have to iterate up several folders) or the user may have changed the folder. An extreme example: the deleted items folder contains both incoming and outgoing mail items.
I have chosen a similar solution to another person (Adi Kini) above where I check the ReceivedByName (I think he chose ReceivedEntryID). The ReceivedByName property is always Null ("") for a sent message, wherever it currently lays. This method can find a sent item that has been dragged to the inbox!. It seems a fairly reliable method of checking.
It seems odd that such an apparently straightforward thing as checking whether mail is incoming or outgoing can trip us up!
I came here with the same problem. Since I will explicitly suggest that user moves the mail to some folder in my usecase, checking Parent would not help...
Regarding MailItem.Sent: are you sure that MailItem.Sent works this way? I just wrote a simple code to run through both my Inbox and SentItems and for almost all of them Sent is true. I assume this is really just an indication whether the mail has been sent (= is not draft)...
I resolved this problem by adding a new UserProperty after e-mail was sent. So when I need to check if e-mail was sent I check this property. This works even if e-mail was moved out of Sent folder. Of course, this works only for newly created e-mails, but you may add this property to all e-mails in Sent folder during first start. The only bug is that UserProperties are printed by default, but this can be overridden.
This is how I check mail type and it works even if mail is moved to any folder. This solution uses PROPERTY ACCESSOR which is available in outlook 2007. Below is the code
string PR_MAIL_HEADER_TAG = "http://schemas.microsoft.com/mapi/proptag/0x007D001E";
Outlook.PropertyAccessor oPropAccessor = mItemProp.PropertyAccessor;
string strHeader = (string)oPropAccessor.GetProperty(PR_MAIL_HEADER_TAG);
if (strHeader == "")
{
// MAIL IS OF TYPE SENTBOX
}
else
{
// MAIL IS OF TYPE INBOX
}
MailItem.sent is true for incoming too.
How about checking MailItem.ReceivedByEntryID. But i am sure this will fail (ReceivedByEntryID will be null for mails in inbox) if you say import from outlook express or maybe some other email program
Iterating thru mail accounts/senderemail may help as you said, but its not fool proof (like if you rename the email address)
Take a look at the MailItem's .Parent property - examine the folder properties to determine if it is the inbox, outbox, drafts, sent items, etc.
You can check if it's inside the Outlook.OlDefaultFolders.olFolderInbox or olFolderOutbox, then there should be other methods you can use to check if it's inside either of these folders!
Outlook.Application _application = new Outlook.Application();
Outlook.MAPIFolder folder = _application.GetNamespace("MAPI").GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
For a simple sended/received control by SMTP address, i suggest an address-check approach.
It can be done in this way:
'Get mail address sender
Dim mailSender As String = GetSenderSMTPAddress(outMailItem)
'Get current user mail address
Dim mailUser As String = OutlookMail2DocScriba.GetUserSMTPAddress(oNameSpace.CurrentUser.AddressEntry)
'If sender and current user matches is a sended mail, otherwise received
If String.Compare(mailSender, mailUser, True) = 0 Then
Return "Sended"
Else
Return "Received"
End If
Public Shared Function GetSenderSMTPAddress(ByVal mail As Outlook.MailItem) As String
'http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.oladdresslisttype.aspx
If mail Is Nothing Then
Throw New ArgumentNullException()
End If
If mail.SenderEmailType = "EX" Then
Dim sender As Outlook.AddressEntry = Nothing
Try
sender = mail.Sender
Catch ex As Exception
'Se non è stato in grado di reperire il sender (Outlook 2007),
'ignoro l'eccezione e procedo.
End Try
If sender IsNot Nothing Then
Return GetUserSMTPAddress(sender)
Else
Return Nothing
End If
Else
Return mail.SenderEmailAddress
End If
End Function
Public Shared Function GetUserSMTPAddress(ByVal sender As Outlook.AddressEntry) As String
'Now we have an AddressEntry representing the Sender
'http://msdn.microsoft.com/en-us/library/office/ff868214(v=office.15).aspx
Const EXCHANGE_USER_ADDRESS_ENTRY As Int32 = 0
Const EXCHANGE_REMOTE_USER_ADDRESS_ENTRY As Int32 = 5
Dim PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
If sender.AddressEntryUserType = EXCHANGE_USER_ADDRESS_ENTRY OrElse _
sender.AddressEntryUserType = EXCHANGE_REMOTE_USER_ADDRESS_ENTRY Then
'Use the ExchangeUser object PrimarySMTPAddress
Dim exchUser As Object = sender.GetExchangeUser()
If exchUser IsNot Nothing Then
Return exchUser.PrimarySmtpAddress
Else
Return Nothing
End If
Else
Return TryCast(sender.PropertyAccessor.GetProperty(PR_SMTP_ADDRESS), String)
End If
End Function
I contradict SenderName vs CurrentUser, to distinguish between emails in inbox or sent folder.
Did you try MailItem.Sent property?
Its true for incoming, and false for outgoing.