EWS: Add userproperties to an EML when saving it? - outlook

In some of my mails, I have stored some userproperties via Outlook...
item.UserProperties.Add("CustID", Outlook.OlUserPropertyType.olText)
item.UserProperties("CustID").Value = custID.ToString
On a Pc (server) without Outlook installed, I want to download mail as EML and store the userproperties (like 'CustID' etc.).
My code for saving the EML:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim service As New ExchangeService(ExchangeVersion.Exchange2013)
service.Credentials = New WebCredentials("my#email.com", "mypsw")
service.Url = New System.Uri("https://outlook.office365.com/EWS/Exchange.asmx")
Dim entryID As String = "00000000C802F40668D27342B788D508E9210A67005DF9A7DEF7194A418C8515031D4262280000E00005DF9A7DEF7194A418C8515031D4262280002A9D18B320000"
Dim id As New ItemId(Convert(service, "my#email.com", entryID))
Dim email As EmailMessage = EmailMessage.Bind(service, id)
Dim ps As PropertySet = New PropertySet(ItemSchema.MimeContent)
email.Load(ps)
Using fileStream = New IO.FileStream("D:\sandbox\_email_test.eml", IO.FileMode.Create)
fileStream.Write(email.MimeContent.Content, 0, email.MimeContent.Content.Length)
End Using
End Sub
Private Function Convert(service As ExchangeService, mailbox As String, entryID As String) As String
Dim originalID As New AlternateId()
originalID.Format = IdFormat.HexEntryId
originalID.Mailbox = mailbox
originalID.UniqueId = entryID 'EntryId retrieved from email in Outlook
Dim altBase As AlternateIdBase = service.ConvertId(originalID, IdFormat.EwsId)
Dim convertedID As AlternateId = DirectCast(altBase, AlternateId)
Dim strConvertedID As String = convertedID.UniqueId
Return strConvertedID
End Function
Is there a way I can store userproperties in an EML? If yes, if I double click the EML to open it in Outlook, can I read back the userproperties from the EML?
Thanks!

User Properties are Mapi/Extended properties which aren't include in the MimeStream of a Message. If you add the properties as X-headers instead then they would be available in the MimeSteam otherwise you would better to export the Message as a MSG file which will give you full fidelity on all MAPI properties. To export as a MSG you will need to use Outlook and maybe look at something like redemption http://www.dimastr.com/redemption/rdo_introduction.htm if you need automation.
Cheers
Glen

Related

Outlook VSTO - Create Mail and save it in Inbox - Set Sender using Outlook Redemption

I basically want to create emails which shall be displayed in the Outlook Inbox using C# Outlook VSTO AddIn.
I have installed the test dlls for Outlook Redemption in my C# Outlook VSTO Addin.
For testing purposes I created a Ribbon Bar with a button. When the button is clicked the following event is triggered:
private void CreateMailItemWithRedemption()
{
//FYI: outlookApp is set in Ribbon load event
//Outlook.Application outlookApp = Globals.ThisAddIn.Application as Microsoft.Office.Interop.Outlook.Application;
var outlookNameSpace = outlookApp.GetNamespace("MAPI");
RDOSession session = new RDOSession();
session.MAPIOBJECT = outlookNameSpace.MAPIOBJECT;
RDOFolder folder = session.GetDefaultFolder(rdoDefaultFolders.olFolderInbox);
RDOMail msg = folder.Items.Add("IPM.Note");
msg.Sent = true;
DateTime dt = new DateTime(2021, 8, 29, 5, 10, 20, DateTimeKind.Utc);
msg.ReceivedTime = dt;
msg.Subject = "Mail created with Redemption";
msg.To = “******#outlook.com”;
msg.Sender = GetAddressEntry("[TestFirstName] [TestLastName]");
msg.Save();
}
It basically works – but for the time being I am stuck with setting the Sender for the new RDOMail which I understand needs to be an RDOAddressEntry.
The GetAddressEntry method looks as follows (with firstname string + lastname string of an existing contact as parameter, like “John Do”):
private RDOAddressEntry GetAddressEntry(string _name)
{
RDOSession session = new RDOSession();
session.MAPIOBJECT = outlookApp.Session.MAPIOBJECT;
RDOAddressList contacts = session.AddressBook.GAL;
RDOAddressEntry contact = contacts.ResolveName(_name);
MessageBox.Show(contact.ToString());
return contact;
}
At contacts.ResolveName an exception is thrown. Do you have an idea what I am doing wrong?
Any hints are welcomed.
Many thanks in advance
Alexander

How to set up sender informtion correctly of exchange address type

In some of the msg files the sender information got deleted accidentally. I want to restore the sender information back in msg file. I am using Redemption library to restore info.
The info is getting restored correctly. I have verified the info using MFCMAPI utility. Click to see sender info with Mapi
But when I open fixed msg with outlook, The sender's exchange canonical name is displayed with sender's display name in UI. e.g "John</O=Exchange/OU=ExchangeAdmin....>" in good msg it only displays "John".
Click to see UI display differences
I am using folowing code to restore sender info.
var PR_SENDER_ADDRTYPE_W = 0x0C1E001F;
var PR_SENDER_NAME_W = 0x0C1A001F;
var PR_SENDER_EMAIL_ADDRESS_W = 0x0C1F001F;
var PR_SENDER_SMTP_ADDRESS = 0x5D01001F;
Redemption.RDOSession oRdoSession = null;
RDOMail oRdoMail = null;
SafeMailItem sfItem = null;
oRdoSession = Redemption.RedemptionLoader.new_RDOSession(); // session = New Redemption.RDOSession
oRdoMail = oRdoSession.GetMessageFromMsgFile(sFilePath);
sfItem = Redemption.RedemptionLoader.new_SafeMailItem(); // CreateObject("redemption.safemailitem")
sfItem.Item = oRdoMail;
bool f_Changed = false;
var f_EntryID = oRdoSession.CreateOneOffEntryID(p_FromDisplayName, p_FromAddressType, p_FromEmailAddress, Type.Missing, Type.Missing);
var ID = oRdoSession.GetAddressEntryFromID(f_EntryID);
oRdoMail.Sender = ID;
oRdoMail.SentOnBehalfOf = ID;
//SetFieldValue is nothing but sfItem.Fields[PR_SENDER_ADDRTYPE_W] = p_FromAddressType
SetFieldValue(sfItem, PR_SENDER_ADDRTYPE_W, "PR_SENDER_ADDRTYPE_W", p_FromAddressType, ref f_Changed);
SetFieldValue(sfItem, PR_SENDER_NAME_W, "PR_SENDER_NAME_W", p_FromDisplayName, ref f_Changed);
SetFieldValue(sfItem, PR_SENDER_SMTP_ADDRESS, "PR_SENDER_SMTP_ADDRESS", p_FromSmtpAddress, ref f_Changed);
SetFieldValue(sfItem, PR_SENDER_EMAIL_ADDRESS_W, "PR_SENDER_EMAIL_ADDRESS_W", p_FromEmailAddress, ref f_Changed);
oRdoMail.Save();
Can you please let me know what am I missing.
For mor properties of sent info please check the screenshot.Click to see ScreenShot
Outlook actually displays the PR_SENT_REPRESENTING_xyz properties.
There is absolutely no reason to create an instance of the SafeMailItem - just use the RDOMail object returned by RDOSession.GetMessageFromMsgFile
What are the values of the p_FromAddressType and p_FromEmailAddress variables? If you know the SMTP address, simply pass it to CreateOneOffEntryID:
var f_EntryID = oRdoSession.CreateOneOffEntryID(p_FromDisplayName, "SMTP", p_FromSmtpAddress, Type.Missing, Type.Missing);

Not able to save a mailItem with protected attachment in outlook using c#

I'm trying to create a copy of a mailItem in my sent folder. Once I create it, I save the msg in the folder. It works for all mailItems , except when I try to save a mailItem with an attachment where I disallow the save attachment permission in outlook. Why does the mailItem.Save() not saving the mailItem only for this scenario?
In the code below, I'm using redemptions to create a copy in sent folder. msg.save() saves all mails but the one I mentioned above. Also I tried saving the mailItem before the creation, but it does not generate entryId.
static void CreateSentFolderMail(Redemption.SafeMailItem newSentMail, string nvdID, Outlook.MailItem mailItem, Redemption.SafeMailItem safeMailItem)
{
RDOFolder folder = Globals.ThisAddIn.session.GetDefaultFolder(rdoDefaultFolders.olFolderSentMail);
RDOMail msg = (RDOMail)folder.Items.Add(newSentMail);
RDOMail originalmsg = Globals.ThisAddIn.session.GetMessageFromID(mailItem.EntryID);
msg.Sent = true;
msg.SentOn = DateTime.Now;
msg.ReceivedTime =msg.CreationTime;
msg.Subject = safeMailItem.Item.Subject;
msg.To = safeMailItem.Item.To;
msg.BCC = safeMailItem.Item.BCC;
msg.Body = safeMailItem.Item.Body;
msg.Recipients = originalmsg.Recipients;
msg.Sender = Globals.ThisAddIn.session.CurrentUser;
msg.SentOnBehalfOf = Globals.ThisAddIn.session.CurrentUser;
msg.SetProps(NVDMailHeaderUtils.PS_INTERNET_HEADERS + NVDMailHeaderUtils.NVD_HEADER_ID, nvdID);
msg.Save();
}
I had used session.GetRDOObjectFromOutlookObject before calling this method to get a RDOAttachment object. But after using this: session.GetRDOObjectFromOutlookObject I was not able to the save the mailitem. Save was not getting executed and hence the EntryId was not getting generated. Due to this issue I was getting an error here : RDOMail originalmsg = Globals.ThisAddIn.session.GetMessageFromID(mailItem.EntryID); saying "invalid entry Id". I installed the new version of redemptions that solved this problem.

Storing emails in sent items of Outlook using add in

I am trying to develop an add in for Outlook in Visual Studio under .net framework 4.0. I used smtp protocol for sending an email from my Outlook addin. I am not able to find the sent mail in sent folder of Outlook.
How do I store sent mail in the sent folder of Outlook?
Till now I have written this code for sending mail.
public bool SendEMail(){
MailMessage mailNew = new MailMessage();
var smtp = new SmtpClient("SmtpServer")
{
EnableSsl = false,
DeliveryMethod = SmtpDeliveryMethod.Network
};
smtp.Port = 587;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.UseDefaultCredentials = false;
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("UserName", "password");
smtp.EnableSsl = false;
smtp.Credentials = credentials;
MailAddress mailFrom = new MailAddress("clark#gmail.com");
mailNew.From = mailFrom;
mailNew.To.Add("someone#gmail.com");
mailNew.Subject = Subject;
mailNew.IsBodyHtml = Html;
mailNew.Body = Body;
smtp.Send(mailNew);
return true;
}
I want to add coding for storing the sent mail in sent folder of Outlook.
You will need to create a fake sent item. Note that messages in the Outlook Object Model are created in the unsent state, which cannot be modified.
The only exception is the post item. The following VB script creates a poat item in the Sent Item folder, resets the message class, reopens it as a regular MailItem (which is now in the sent state). Note that you cannot set the sender related properties using OOM alone and you cannot set the sent/received dates.
'create PostItem
set msg = Application.Session.GetDefaultFolder(olFolderSentMail).Items.Add("IPM.Post")
msg.MessageClass = "IPM.Note"
msg.Subject = "fake sent email"
msg.Body = "test"
msg.Save
vEntryId = msg.EntryID
set msg = Nothing 'release the mesage
'and reopen it as MailItem
set msg = Application.Session.GetItemFromID(vEntryId)
'make sure PR_ICON_INDEX is right
msg.PropertyAccessor.SetProperty "http://schemas.microsoft.com/mapi/proptag/0x10800003", -1
set vRecip = msg.Recipients.Add("fakeuser#domain.demo")
vRecip.Resolve
msg.Save
If using Redemption is an option, it lets you set the sent state before the first save (MAPI limitation) and allows to set the sender and date properties correctly:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set msg = Session.GetDefaultFolder(olFolderSentMail).Items.Add("IPM.Note")
msg.Sent = true
msg.Subject = "fake sent email"
msg.Body = "test"
set vRecip = msg.Recipients.Add("fakeuser#domain.demo")
vRecip.Resolve
'dates
msg.SentOn = Now
msg.ReceivedTime = Now
'create fake sender
vSenderEntryID = Session.AddressBook.CreateOneOffEntryID("the sender", "SMTP", "me#domain.demo", true, true)
set vSender = Session.AddressBook.GetAddressEntryFromID(vSenderEntryID)
msg.Sender = vSender
msg.SentOnBehalfOf = vSender
msg.Save

Outlook custom plugin code not working as expected (Downlaod Email attachment)

I am tring to save attachemnt from a incoming mail in outllok. This is my code. My issue is it downloads correctly when email arrives(when my laptop is open), but this mail is scheduled everyday at 6:00 AM, I open my laptop at 9 and mail is already present and it is not downloading as expected?Do i need to do anything with code?
const string destinationDirectory = #"\\prod_data\Service Now\";
Outlook.MAPIFolder inBox = this.Application.ActiveExplorer()
.Session.GetDefaultFolder(Outlook
.OlDefaultFolders.olFolderInbox);
Outlook.Items inBoxItems = inBox.Items;
Outlook.MailItem newEmail = null;
inBoxItems = inBoxItems.Restrict("[Unread] = true");
try
{
foreach (object collectionItem in inBoxItems)
{
newEmail = collectionItem as Outlook.MailItem;
if (newEmail != null)
{
if (newEmail.Attachments.Count > 0)
{
for (int i = 1; i <= newEmail
.Attachments.Count; i++)
{
if (newEmail.Attachments[i].FileName.Contains( "LogicView Issue Report"))
{
newEmail.Attachments[i].SaveAsFile(destinationDirectory +
newEmail.Attachments[i].FileName);
}
}
}
}
}
}
I'd suggest checking out the MarkForDownload property value. It returns an OlRemoteStatus constant that determines the status of an item once it is received by a remote user. For example:
Sub DownloadItems()
Dim mpfInbox As Outlook.Folder
Dim obj As Object
Dim i As Integer
Set mpfInbox = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
'Loop all items in the Inbox folder
For i = 1 To mpfInbox.Items.Count
Set obj = mpfInbox.Items.Item(i)
'Verify if the state of the item is olHeaderOnly
If obj.DownloadState = olHeaderOnly Then
MsgBox ("This item has not been fully downloaded.")
'Mark the item to be downloaded.
obj.MarkForDownload = olMarkedForDownload
End If
Next
End Sub
You can use the Start method of the SyncObject class to begin synchronizing a user's folders using the specified Send\Receive group.
Do not use Application.NewMail event - it fires only when Outlook is running at the time the email is received by the Exchange server.
Use Items.ItemAdd event on the Inbox folder (Namespace.GetDefaultFolder(olFolderInbox)) - it will fire when the email downloaded to the cached store when Outlook synchronizes the Inbox folder (assuming you are using cached mode). If Outlook is online, no events will fire. In that case, you can use Items.Find/FindNext to process all unread messages ([Unread] = 'true').
//declare on the global/class level to make sure
//it does not get garbage collected
private Outlook.Items inBoxItems;
...
//in your addin startup code
inBoxItems = inBox.Items
inBoxItems.ItemAdd += inboxItemsItemAdd;
...
private void inboxItemsItemAdd(object item)
{
...
}

Resources