I am writing simple Outlook program in C# which records MailItem’s Recipients for sent mail. To build that I am hooking into Outlook Mailitem Send event to get Recipient collection. Also to avoid Outlook security prompt I am using Redemption SafeMailItem.
For reading Recipient collection I am assigning MailItem to SafeMailItem and read Recipients. However Recipient collection won’t be same if MailItem has unsaved changes. In order to copy Recipient collection, MailItem requires to be saved and then access via Redemption SafeMailItem.
Here is example.
//event handler
void _MailItemSend(ref bool Cancel)
{
SafeMailItem safeMailItem = (SafeMailItem)Activator.CreateInstance(Type.GetTypeFromProgID(RDOCustomClasses.SafeMailItem));
SafeRecipients recipients = null;
safeMailItem.Item = mailItem; // Assigning original mailItem which getting sent by outlook without saving it (just compose & send email before it get autosaved by outlook or manually)
recipients = safeMailItem.Recipients
// If mailItem have unsaved changes safeMailItem.Recipients will be different.
recipients.Count != mailItem.Recipients.Count;
}
So I believe calling Save() makes sense but I am not changing anything and calling Save() is causing another issue. When I try to quit Outlook it says:
there are unsaved changes “ do you want to save change”.
I tried accessing directly Mailitem.Recipients (it has latest and unsaved recipient list before mail getting send) but it creates Outlook security prompt. If I used Redemption it requires call to save before accessing it which creates other issue.
Is there a better way to receive Outlook Sent Mail Recipients in safe manner without modification ? Your suggestion will be appreciated.
Related
When I reply to incoming mail, attachs are deleted. How do I add attachments to new mail with vsto addin?
Do you mean the original email attachments are removed from the new item? Why is it a problem? That is the expected behavior. Note that embedded images attachments are copied to the new message.
You can save the original attachments by looping through the MailItem.Attachments collection and calling Attachment.SaveAsFile. You can then add the attachments to the new message by calling MailItem.Attachments.Add.
I'm working on an Outlook Add-in, using office.js, where users can send secure emails using backend service.
In compose mode, when the user sends the email, using the add-in of course, the add-in will then move the message to "Sent Items" folder using the Outlook API /message/{id}/move and everything goes OK with the exception that the message in question still being marked as "Draft" by Outlook which is really annoying and does confuse the user who just sent the email by telling him that "this message hasn't been sent"
I searched through the API to see if there is a way to mark an email as "SENT" in order to prevent Outlook from showing this RED hint but with no luck so far!
So, My Question Is: Is there any way to overcome this misleading msg by marking the email as it was sent by Outlook?
Thanks in advance.
Finally, I was able to achieve a perfect solution for this challenge.
Based on:
#BrianClink's comment
This answer (Which uses Graph API but Outlook REST API): Microsoft Graph API mail office 365: Is any option create inbox message NOT as Draft?
The approach/steps I followed to mark a mailItem as "SENT" (and not shown as 'draft') and put it in "SentItems" Folder are as follow:
First, Save the mailItem as "draft" using Office.context.mailbox.item.currentMail.saveAsync then retrieve its ID
Clone this draft mailItem properties eg: 'Sender', 'Subject', 'Body', 'ToRecipients'..etc so you get an exact copy of it.
With the newly cloned mailItem, add '[SingleValueExtendedProperties]' property with this value :
[
{
PropertyId: 'Integer 0x0E07',
Value: '1'
}
];
Serialize the new item as JSON and POST it to "sentitems" folder as follows:
xhr.open('POST', restHost + '/v2.0/me/MailFolders/sentitems/messages/');
xhr.send(clonedEmailJson);
On success, with xhr.status=201 [created], Remove the draft mailitem using a [DELETE] request
And you will end up having a new mail item created in your "sentItems" folder which appears as it was sent by Outlook :)
This was a very helpful solution to me because my users are using my add-in to send secure emails (using 3rd party API) and NOT Outlook, So, I wanted them to have the same UX/feeling as when they use Outlook.
Note:
Although the solution worked for me perfectly, it came with a price!
On slow internet connections or in case emails containing large attachments, the process can be remarkably slow, because the addin will first save the draft to the remote Exchange Server, get its ID, then duplicate it and send it again to the server, then remove the draft-ed one.
We are trying to save attachments selected by the user using Redemption but stumbled on filename escaping inconsistency between VSTO and Redemption. What we do:
By attachment context menu save attachmentSelection[1] index and filename to the db and also message entryId and storeId.
After a while (maybe even after Outlook restart) we need to save this attachment to file. To do this, we get that e-mail with Redemption by id, get attachment by index (rdoMail.Attachments[index]) and also ensure that filename match, since according to this:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.interop.outlook.attachment.index?view=outlook-pia#Microsoft_Office_Interop_Outlook_Attachment_Index
index property is valid only during the current session. Although it is not clear what they mean. Can it change if the e-mail is saved and sent already? Or received?
For reply e-mail VSTO Attachment.Filename is "RE Test.msg" and RDOAttachment.Filename is "RE_ Test.msg" (this is msg attachment of another e-mail).
So, the questions are:
why it is different and is it documented somewhere? Can we, for example, replace _ with string.Empty for Redemption filenames or there can be other cases?
Or maybe there is a way to get RDOAttachment from Outlook Attachment object somehow?
Can we rely on that Redemption attachment index is the same as Outlook one?
Sounds like you are dealing with an embedded message attachment - unlike regular by-value attachments that expose the PR_ATTACH_LONG_FILENAME MAPI property, there is no intrinsic file name property for the embedded attachments. Both OOM and Redemption generate that property from the the embedded message subject, whcih you cam access through RDOAttachment.EmbeddedMsg.Subject. OOM does not expose embedded message attachments at all.
Yes, use RDOSession.GetRDOObjectFromOUtlookObject method
The index usually does not change, but it might. MAPI itself uses PR_ATTACH_NUM to open the attachment using IMessage::OpenAttach, but it can be different based on how the message was opened - a fake IMessage returned from MailItem.MAPIOBJECT can have a different value of PR_ATTACH_NUM from the native message returned by the store provider.
I'm developing an Outlook add-in that allows the user to save an email to the filesystem just after it's been sent.
To achieve this, I intercept the Application.ItemSend event, and inside my handler I call MailItem.SaveAs(...). It works, basically.
The problem I'm facing is that, when I open the file saved, the email is in draft state. I mean, the recipients, subject and message body can be modified, and the email can be resent. I want the email to be in "sent" state, i.e. not modifiable.
It looks like Outlook API does not provide any event dispatched after the email is sent. Only before, and this is my pain.
Do you have any idea to perform this?
Thanks a lot for your help!
Nico
the earliest you can save the message in the sent state and with the sender properties populated is when Items.ItemAdd event fires on the Sent Items folder.
In a Outlook addin I want to set PS_INTERNET_HEADERS properties on outgoing emails/meeting requests. I can see that for meetings those properties are not preserved when I open the incoming meeting (I send it to myself) - the email header for my property does not exist and I cannot see the property in OutlookSpy. for regular emails (not meetings) properties are preserved fine.
I can also reproduce this behavior with OutlookSpy - I create a new meeting, in OutlookSpy I add a PS_INTERNET_HEADERS named property, and send the meeting to myself. when I open the incoming meeting the property is gone. (it also does not appear when I open the meeting from the SentItems)
When and how do you set the properties? Keep in mind that AppointmentItem is never sent. When you call AppointmentItem.Send, a new MeetingItem object is created and sent. You can only access it in the Application.ItemSend event handler.