I use the following code to assign some data to an appropriate ContactItem (Sender) of given MailItem. If Sender.GetContact() returns null, I'm trying to create a new ContactItem.
Outlook.MailItem myItem = (Outlook.MailItem)this.OutlookItem;
Outlook.ContactItem currentContact = myItem.Sender.GetContact();
if (currentContact != null)
{
currentContact.Body = "Example";
currentContact.Save();
}
else
{
currentContact = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olContactItem) as Outlook.ContactItem;
currentContact.Email1DisplayName = myItem.SenderName;
currentContact.Email1Address = myItem.SenderEmailAddress;
currentContact.Email1AddressType = myItem.SenderEmailType;
currentContact.Body = "Example";
currentContact.Save();
}
But this does not seem to work fine for me. The next time I'm getting the contact of that MailItem (see the following code), it returns null. Again. And again.
Outlook.MailItem myItem = (Outlook.MailItem)this.OutlookItem;
Outlook.ContactItem currentContact = myItem.Sender.GetContact();
Is there something wrong? It seems like that new ContactItem is not assigned to Sender.
GetContact will return ContactItem object only if the outgoing message (does not work for incoming) had the contact explicitly added as a recipient.
GetContact will not check if you happen to have a contact item with the same email address.
If you need to find a matching contact, explicitly use MAPIFolder.Items.Find on the Contacts folder.
Related
Im trying to load and use the properties of EWS Items. During my codes execution the object loses it's value.
Im loading messageId, attachments and subjuect.
Here's my code:
'''
FindItemsResults<Item> items = EwsHelper.GetMails(credentials); //Gets the items from the exchange service object. This method populate FindItemResults. It works.
//Find correct EmailMessage with messageId (mailInput.MessageId is a param to my code to verify that I found the correct mail.
string messageId = mailInput.MessageId;
//The Id.UniqueId can be found. The property is loaded inside of the "EwsHelper.GetMails".
foreach (Item item in items.Where(i => i.Id.UniqueId == messageId))
{
//Here im loading all the properties I need once again. I can verify that the object does have loaded property through the debugger. Everything is fine!
item.Load(new PropertySet(ItemSchema.Subject,
ItemSchema.Id, ItemSchema.Attachments));
if (item == null || !(item is EmailMessage))
throw new Exception();
dynamic fileObj = new ExpandoObject();
//Here the item.Subject (which recently was loaded) is null... Cant figure out why?!
fileObj.Filename = $"{item.Subject.RemoveInvalidFileNameChar()}.msg";
}
'''
I want to programmatically add with C# recipients to an existing/composing MailItem. When I add a recipient like this:
Microsoft.Office.Interop.Outlook.Inspector inspector = Globals.ThisAddIn.Application.ActiveInspector();
Microsoft.Office.Interop.Outlook.MailItem item = inspector.CurrentItem as Microsoft.Office.Interop.Outlook.MailItem;
Microsoft.Office.Interop.Outlook.Recipient mRecipient = item.Recipients.Add("test.user");
mRecipient.Type = (int)Microsoft.Office.Interop.Outlook.OlMailRecipientType.olBCC;
it appears in the TO field of the MailItem.
When I do something like this:
item.BCC = "test.user";
it appears correclty...
Is there a way to to add the recipient with the first method (Type.olBCC) and show it up in the BCC mail field (2nd snippet)?
I want to go this way because then I can iterate through all recipients and remove some when a special condition is called.
The problem is when I remove the added BCC recipient with
item.BCC = "";
all recpients were deleted in the BCC field.
Apparently we are all missing the point: https://msdn.microsoft.com/en-us/vba/outlook-vba/articles/recipients-object-outlook
According to this
Microsoft.Office.Interop.Outlook.Recipient mRecipient = item.Recipients.Add("test.user");
mRecipient..Type = olCC // at a guess here olBCC would be BCC...
We can modify the list as a list.. :)
Note: I couldnt find olCC in my list.. but maybe I need to look harder.
Note2! Found it.
OlMailRecipientType. has olTo, olOriginator, olCC and olBCC
There you go. so mRecipient.Type = OlMailRecipientType.olBCC should do the trick
The following - opened a new mail item with joe.bloggs in bcc:
olApplication = new Microsoft.Office.Interop.Outlook.Application();
m = olApplication.CreateItem(OlItemType.olMailItem);
Recipient r = m.Recipients.Add("joe.bloggs");
r.Type = (int)OlMailRecipientType.olBCC;
m.Display(true);
Having saved a draft and worked out how to get hold of it as 1 item apparently isnt items[0] ..
the following also works:
Microsoft.Office.Interop.Outlook.MAPIFolder folderDrafts = ns.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderDrafts);
if (folderDrafts.Items.Count > 0)
{
m = (Microsoft.Office.Interop.Outlook.MailItem)folderDrafts.Items[1];
Recipient r = m.Recipients.Add("joe.bloggs");
r.Type = (int)OlMailRecipientType.olBCC;
m.Display(true);
}
As the user BugFinder mentioned there is a workaround neccessary since the UI adds the BCC recipient to the olTO field. I solved this with first adding a dummy, then add the BCC and remove the dummy:
Microsoft.Office.Interop.Outlook.Inspector inspector = Globals.ThisAddIn.Application.ActiveInspector();
Microsoft.Office.Interop.Outlook.MailItem item = inspector.CurrentItem as Microsoft.Office.Interop.Outlook.MailItem;
//Create dummy recipient object for UI bug
Microsoft.Office.Interop.Outlook.Recipient dummy =
item.Recipients.Add("bugDummy");
dummy.Type = (int)Microsoft.Office.Interop.Outlook.OlMailRecipientType.olBCC;
//Create the BCC object that will be used
Microsoft.Office.Interop.Outlook.Recipient mRecipient = item.Recipients.Add("test#user.de");
mRecipient.Type = (int)Microsoft.Office.Interop.Outlook.OlMailRecipientType.olBCC;
//iterate through the recipients and delete the dummy
foreach (Microsoft.Office.Interop.Outlook.Recipient recipient in item.Recipients)
{
if (string.Compare(recipient.Name, "bugDummy", true) == 0)
{
recipient.Delete();
break;
}
}
My company needs an add-in for automatically adding offers to the email when it is the first time we send an email to a recipient.
My question is :
How can I check if this is the first time the user sends an email to the recipients?
I tried this but I receive error that Recipient is unknown property. And I also think that this is not the right approach...
object folderItem;
Boolean AlreadyEmailed = false;
if (mail != null)
{
const string PR_SMTP_ADDRESS =
"http://schemas.microsoft.com/mapi/proptag/0x39FE001E";
Outlook.Recipients recips = mail.Recipients;
foreach (Outlook.Recipient recip in recips)
{
Outlook.PropertyAccessor pa = recip.PropertyAccessor;
string smtpAddress =
pa.GetProperty(PR_SMTP_ADDRESS).ToString();
string filter = "[Recipient] = 'John#foo.com'";
filter = filter.Replace("John#foo.com", smtpAddress);
Debug.WriteLine(filter);
folderItem = items.Restrict(filter);
if(folderItem != null)
{
Debug.WriteLine("We found items that have the filter");
AlreadyEmailed = true;
}
//Debug.WriteLine(recip.Name + " SMTP=" + smtpAddress);
}
if(!AlreadyEmailed)
{
Debug.WriteLine("This is the first time we email ... ");
}
}
The Sent property of the MailItem class returns a Boolean value that indicates if a message has been sent. In general, there are three different kinds of messages: sent, posted, and saved. Sent messages are items sent to a recipient or public folder. Posted messages are created in a public folder. Saved messages are created and saved without either sending or posting.
Also you may use the following Extended MAPI properties that deal with the message state (replied/forwarded):
PR_ICON_INDEX (http://schemas.microsoft.com/mapi/proptag/0x10800003)
PR_LAST_VERB_EXECUTED (the DASL name is http://schemas.microsoft.com/mapi/proptag/0x10810003)
PR_LAST_VERB_EXECUTION_TIME (0x10820040)
To get these values use the PropertyAccessor class (see the corresponding properties of Outlook items).
Be aware, new Outlook items don't have the EntryID property set.
You can Use To/CC/BCC properties in Items.Find/Restrict. Note that it is better to use Find in your case since you only need a single match, not all of them. Also note that Restrict will not return null if no matches are found, but rather an Items collection with Items.Count == 0.
That being said, To/CC/BCC might not include addresses, only names, so search won't help you. You can still loop through all items in the folder and explicitly check the Recipients collection of each item, but that will be hugely inefficient.
On the Extended MAPI level (C++ or Delphi), one can create subrestrictions on message recipients (or attachments), but the Outlook Object Model does not expose that functionality.
If using Redemption is an option (I am its author), its implementation of Find/Restrict does support queries on the Recipients collection:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set YourOutlookFolder = Application.ActiveExplorer.CurrentFolder
set rFolder = Session.GetFolderFromID(YourOutlookFolder.EntryID)
set rItems = rFolder.Items
set rMsg = rItems.Find("Recipients LIKE 'John#foo.com' ")
while not (rMsg Is Nothing)
Debug.print rMsg.Subject
set rMsg = rItems.FindNext
wend
In C# (not tested):
Redemption.RDOSession Session = new Redemption.RDOSession();
Session.MAPIOBJECT = Application.Session.MAPIOBJECT;
set rFolder = Session.GetFolderFromID(YourOutlookFolder.EntryID);
Redemption.RDOMail rMsg = rFolder.Items.Find("Recipients LIKE 'John#foo.com' ") ;
AlreadyEmailed = rMsg != null;
I cannot work out how I can do what I need to do.
I have a method called 'MarkAsRead' that takes an ItemID and should mark the mail item as read.
But it seems that the Item doesn't have an 'IsRead' proeprty, only an email does, so I need to cast my Exchange WebServices mail item to an email message.
here is the code:
try
{
System.Diagnostics.Debugger.Break();
//creates an object that will represent the desired mailbox
Mailbox mb = new Mailbox(common.strInboxURL);
//creates a folder object that will point to inbox fold
FolderId fid = new FolderId(WellKnownFolderName.Inbox, mb);
//this will bind the mailbox you're looking for using your service instance
Microsoft.Exchange.WebServices.Data.Folder inbox = Microsoft.Exchange.WebServices.Data.Folder.Bind(service, fid);
//// if the property is not loaded yet, first load it
//mail.Load(PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.IsRead));
//if (!mail.IsRead) // check that you don't update and create unneeded traffic
//{
// mail.IsRead = true; // mark as read
// mail.Update(ConflictResolutionMode.AutoResolve); // persist changes
//}
// As a best practice, limit the properties returned to only those that are required.
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject);
// Bind to the existing item by using the ItemId.
// This method call results in a GetItem call to EWS.
Item item = Item.Bind(service, itemId, propSet);
EmailMessage mail = Item.Bind(service, itemId, propSet);
item.Load(new PropertySet(BasePropertySet.IdOnly,EmailMessageSchema.IsRead));
item.IsRead = true;
item.Update(ConflictResolutionMode.AlwaysOverwrite);
return true;
}
I am trying to do something like this:
// if the property is not loaded yet, first load it
mail.Load(PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.IsRead));
if (!mail.IsRead) // check that you don't update and create unneeded traffic
{
mail.IsRead = true; // mark as read
mail.Update(ConflictResolutionMode.AutoResolve); // persist changes
}
unfortunately I need to be able to get a unique email message from the item.
how can I do that please?
Philip-
You can add EmailMessageSchema.IsRead to your property set, so that you can get it in your Bind call, and then you don't have to call Load at all.
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly,
ItemSchema.Subject, EmailMessageSchema.IsRead);
The EmailClass derives from the Item class, so Bind works on both. So you can do the following:
EmailMessage mail = EmailMessage.Bind(service, itemId, propSet);
Put that together and you've got this:
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, EmailMessageSchema.IsRead);
EmailMessage mail = EmailMessage.Bind(service, itemId, propSet);
if (!mail.IsRead) // check that you don't update and create unneeded traffic
{
mail.IsRead = true; // mark as read
mail.Update(ConflictResolutionMode.AutoResolve); // persist changes
}
Philip,
When testing my code I added just a little bit to the Item.Bind() from your code to make this work:
EmailMessage mail = Item.Bind(service, itemId, propSet) as EmailMessage;
The as EmailMessage will cast it to the appropriate type for you. After that I was able to see the isRead property.
I hope this helps. If this does resolve your problem, please mark the post as answered.
Thanks,
--- Bob ---
I am a newbie developer and I have been stuck with EWS for hours now. I need to read through the most recent emails, get all the unread emails and use the data from them to do some stuff.
At this moment My code looks like this.
static void Main(string[] args)
{
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = new WebCredentials("support#mycompany.com", "mysupersuperdupersecretpassword");
service.AutodiscoverUrl("support#mycompany.com", RedirectionUrlValidationCallback);
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox,new ItemView(2));
foreach (Item item in findResults.Items)
{
// works perfectly until here
Console.WriteLine(item.Subject);
Console.WriteLine('\n');
item.Load();
string temp = item.Body.Text;
// I can't seem to get TextBody to work. so I used a RegEx Match match = Regex.Match(temp, "<body>.*?</body>", RegexOptions.Singleline);
string result = match.Value;
result = result.Replace("<body>", "");
result = result.Replace("</body>", "");
Console.Write(result);
Console.WriteLine('\n');
//Now the email boddy is fine but IsNew always returns false.
if (item.IsNew)
{
Console.WriteLine("This message is unread!");
}
else
{
Console.WriteLine("This message is read!");
}
}
}
I have googled and tried and googled some more and I am stuck. How do I now which emails are read, is there a way to get the email body text that's more effective than what I have done ? Any help would be super appreciated.
The MSDN article for usage is pretty good if you haven't already read it.
For your issue, cast your item to an EmailMessage
foreach (Item item in findResults.Items)
{
var mailItem = (EmailMessage)item;
// works perfectly until here
Console.WriteLine(mailItem.Subject);
}
I did notice you are not using Property Sets, but having only used EWS for event notifications and not going through existing mails, it may be different.
UPDATE Additions in light of your changes
use this for your Property Set
new PropertySet(BasePropertySet.FirstClassProperties) {
RequestedBodyType = BodyType.Text
};
Also this reads a little nicer and uses the Body.Text property
foreach (Item myItem in findResults.Items.Where(i=>i is EmailMessage))
{
var mailItem = myItem as EmailMessage;
Console.WriteLine(mailItem.Subject);
mailItem.Load(new PropertySet(BasePropertySet.FirstClassProperties) {
RequestedBodyType = BodyType.Text
}); // Adding this parameter does the trick :)
Console.WriteLine(mailItem.Body.Text);
if(! mailItem.IsRead)
Console.WriteLine("Who is Your Daddy!!!!");
}