How do I save outlook Mailitem as sent mail - c#

I have created an Outlook mail item and want to save it in a folder as a sent mail. I was able to set sender mail using mail.SentOnBehalfofName. How do I add Date field to this. I have some eml emails which I want to add to folder without a paid library. I was able to parse and save it to an outlook folder but the date field is set to None. Can someone help either to set the date field to the outlook mailitem object or a way to create mail Items that can be saved in outlook with all the properties?

Firstly, item's sent state can only be changed before it is saved for the very first time (MAPI limitation). Secondly, Outlook always creates olMailItem objects in the unsent state. The only item created in the sent state is the PostItem (olPostItem). You can create a PostItem, change its MessageClass property to "IPM.Note", save it, then release it using Marshal.ReleaseComObject (to make sure Outlook forgets about it), then reopen it by calingNamespace.GetItemFromID - this time Outlook should return back a MailItem object (instead of the original PostItem).
Keep in mind that the icon will be wrong, hence the post icon needs to be removed - delete the PR_ICON_INDEX property (DASL name http://schemas.microsoft.com/mapi/proptag/0x10800003) using MailItem.PropertyAccessor.DeleteProperty.
Also keep in mind that Outlook will not let you set some properties it considers "important" - such as the message dates, sender entry id, etc. And setting just the SentOnBehalfOfName property won't be enough - the sender entry ids must be set, or the user won't be able to correctly reply to that message.
If using Redemption (I am its author) is an option, creating a message in the sent state is as easy as
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set Inbox = Session.GetDefaultFolder(olFolderInbox)
set Msg = Inbox.Items.Add
Msg.Sent = true
set CU = Session.CurrentUser
set recip = Msg.Recipients.AddEx(CU.Name, CU.SmtpAddress, "SMTP", olTo)
Msg.Subject = "fake received message"
Msg.Body = "just a test"
vSenderEntryId = Session.AddressBook.CreateOneOffEntryID("Joe The Sender", "SMTP", "joe#domain.demo", false, true)
set vSender = Session.AddressBook.GetAddressEntryFromID(vSenderEntryId)
Msg.Sender = vSender
Msg.SentOnBehalfOf = vSender
Msg.SentOn = Now
Msg.ReceivedTime = Now
Msg.Save

Related

C# Outlook Plugin - Create new item into Sent Box without send that email

I'm writing a plugin for outlook, I want to create new item into Sent Box but i don't want to send it, just save it to Sent Box.
Pls, help me!
Outlook Object Model will not, generally, let you create a message in the sent state - MailItem.Sent property is read-only. Even on the MAPI level (C++ or Delphi), MSGFLAG_UNSENT bit can be removed from the PR_MESSAGE_FLAGS property only before the message is saved for the very first time. The only kind of item created by OOM in the sent state is a post item, so in theory, you can create a post item, save it, reset its MessageClass property to "IPM.Note", dereference it, reopen by the entry id - you will now have a MailItem in the sent state. You will not have to set all the sender and recipient properties (about a dozen of them) and remove post specific properties - take a look at a sent message with OutlookSpy (I am its author - click IMessage button).
If using Redemption (I am also its author - any language) is an option, it can create a fake sent message easily:
Set MySession = CreateObject("Redemption.RDOSession")
MySession.MAPIOBJECT = Application.Session.MAPIOBJECT
Set Folder = MySession.GetDefaultFolder(olFolderSentMail)
Set msg = Folder.Items.Add("IPM.Note")
msg.Sent = True
msg.Recipients.AddEx "The user", "user#domain.demo", "SMTP", olTo
msg.Sender = MySession.CurrentUser
msg.SentOnBehalfOf = MySession.CurrentUser
msg.subject = "Test sent message"
msg.Body = "test body"
msg.SentOn = Now
msg.ReceivedTime = Now
msg.Save

OUTLOOK VSTO: delete an email after sending it

I'm working with vsto for outlook. Create an email message and send it to recipient.
I want to delete the e-mail from "sent items" (or prevent its entrance there) but can not find a way to do it.
During my attempts I tried to filter emails in "sent items" by "find" and "restrict" functions on the "recipient" but I got an error of "Condition is not valid" or "Cannot parse condition. Error at "...."".
My Code is:
MailItem reportEmail = Globals.ThisAddIn.Application.CreateItem(OlItemType.olMailItem);
reportEmail.Subject = subject;
reportEmail.To = TeamEmailAlias;
reportEmail.Send();
How can I delete the mail from "Sent Items" now ?
thanks,
You just need to set up the DeleteAfterSubmit property of the MailItem class which allows to set a Boolean value that is True if a copy of the mail message is not saved upon being sent, and False if a copy is saved.
MailItem reportEmail = Globals.ThisAddIn.Application.CreateItem(OlItemType.olMailItem);
reportEmail.DeleteAfterSubmit = true;
reportEmail.Subject = subject;
reportEmail.To = TeamEmailAlias;
reportEmail.Send();
There is a MailItem.Delete() method, which should delete it from whatever folder it is in. This article on MSDN explains it, and also offers extra resources. You can also delete all items in a folder by using FolderName.Item(n).Delete().

How to access a user property of a custom outlook mail item with Redemption in C#

I’m trying to write a C# application that opens up a outlook custom mail item and fill in multiple user properties. I was able to do so by using the Microsoft Outlook Interop. But I had the annoying security warning each time I tried to change some user property. I found out that Redemption is the perfect tool to avoid this. But when I try to change a user property, Redemption creates a new one instead of using the already existing one.
This is the code I used to change the property with Outlook Interop (Pops up a security warning) :
string customPropertyNamespace = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/";
Outlook._Items oItems = oPublicFolder.Folders["Babillards"].Folders["SYSOTI"].Folders["MEP"].Items;
Outlook._MailItem oMep = oItems.Add("ipm.note.mep");
oMep.PropertyAccessor.SetProperty(customPropertyNamespace + "prop1", "SomeText");
oMep.Display(false);
This all works fine, except for the security warning...
This is the redemption code I'm trying to use :
string customPropertyGUID = "{00020329-0000-0000-C000-000000000046}";
Outlook._Items oItems = oPublicFolder.Folders["Babillards"].Folders["SYSOTI"].Folders["MEP"].Items;
Outlook._MailItem oMep = oItems.Add("ipm.note.mep");
Redemption.SafeMailItem Mep = new Redemption.SafeMailItem();
Mep.Item = oMep;
Mep.set_Fields(Mep.GetIDsFromNames(customPropertyGUID, "prop1"), "SomeText");
oMep.Display(false);
From what I understood this should work. But instead, my mail page opens with all my fields empty. By using OutlookSpy I found out that Redemption creates a new property with this DASL :
http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/prop1/0x0000001F
instead of :
http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/prop1
Can somebody help me? I also tried using the Redemption.MAPIUtils but I ended up with exactly the same result. Is there a way to change a user property by passing the DASL instead of a GUID and ID ?
The two property names are exactly the same - the last part (0x0000001F) is simply property type (= PT_UNICODE). What exactly do you mean by "my mail page opens with all my fields empty"? Do you have a custom form with controls bound to user fields?
Also keep in mind that Outlook might not see all the latest changes made with MAPI until the item is completely dereferenced and reopened. Do o use the data after you restart Outlook and reopen the existing item?
To avoid Outlook caching problem, try to create the message using Redemption, set the property, and only then open the message using Outlook. Somethiong like the following (off the top of my head):
string customPropertyNamespace = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/";
Outlook.Forlder oFolder = oPublicFolder.Folders["Babillards"].Folders["SYSOTI"].Folders["MEP"];
Redemption.RDOSession session = new RDOSesssion();
session.MAPUIOBJECT = Application.Session.MAPIOBJECT;
Redemption.RDOFolder rFolder = session.(RDOFolder)session.GetRDOObjectfromOutlookObject(oFolder);
Redemption.RDOMail rMsg = rFolder.Items.Add("ipm.note.mep");
rMsg.Fields[customPropertyNamespace + "prop1"] = "SomeText";
rMsg.Save();
//reopen in Outlook and display. Or you can use rMsg.Display()
Outlook._MailItem oMep = Application.Session.GetItemFromID(rMsg.EntryID);
oMep.Display(false);

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.

Outlook MailItem: How to distinguish whether mail is incoming or outgoing?

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.

Categories