How to access the subject of a compose mail item in Outlook - c#

In Outlook, I can set the subject for a new message (when composing a new mail message), but I want to prepend text. So I need to get the subject first, and then set it.
Outlook.Application application = Globals.ThisAddIn.Application;
Outlook.Inspector inspector = application.ActiveInspector();
Outlook.MailItem myMailItem = (Outlook.MailItem)inspector.CurrentItem;
if (myMailItem != null && !string.IsNullOrEmpty(myMailItem.Subject))
{
myMailItem.Subject = "Following up on your order";
}
This code works on replies, but not for new messages, because in that case, myMailItem is null.

This is what I was looking for:
if (thisMailItem != null)
{
thisMailItem.Save();
if (thisMailItem.EntryID != null)
{
thisMailItem.Subject = "prepended text: " + thisMailItem.Subject;
thisMailItem.Send();
}
}
The subject was null until the mail item had been saved, either because it was sent, or as a draft. We can save it programmatically and then get the subject.
One other note: if the subject is blank at the time of saving, it will still show as null.

Related

Only get the latest reply text in an Outlook Email using VSTO and C#

I have gone through many links already but none of them seems to be working. My problem is that in an Outlook Add-In written using C# and VSTO, I am looking to capture the text of the latest Reply email to a thread.
The problem is that all the properties on a MailItem object such as Body, HTMLBody etc give the entire text of the email including past replies. I am looking to somehow only get the most recent text. And I need to be able to do this considering multiple languages in an email.
Here is what i have tried
Using Bookmarks on the MailEditor - There seems to be no more _MailOriginal bookmark with exchange and Outlook
Somehow trying to get hold off MIME properties - I don't know enough on which properties to pick and how to use them to parse the recent text.
You cannot do that even in theory: imagine a user typing at the top of the message (e.g. "see below") and then inserting/deleting various pieces in the message body below (I do that all the time). You are lucky if the font color is different.
You can try to compare the original with the new and figure out the diff, but that requires access to the original message. You can look at the PR_IN_REPLY_TO_ID MAPI property (DASL name http://schemas.microsoft.com/mapi/proptag/0x1042001F) and try to find the original message either in the Inbox or the Sent Items folder. Note that in the latter case (Sent Items folder) the property might not be available on the cached message, you'd need to search the online version of the folder (cannot do that in OOM, you'd need Extended MAPI in C++ or Delphi or Redemption in any language).
The Outlook object model doesn't provide anything for that. You need to parse the message body string on your own.
Also, you can iterate over all items in the conversation and detect each of them in the latest/recent item. By removing older items you can get the latest. The following example shows how to get and display mail items in a conversation.
void DemoConversation()
{
object selectedItem = Application.ActiveExplorer().Selection[1];
// For this example, you will work only with
//MailItem. Other item types such as
//MeetingItem and PostItem can participate
//in Conversation.
if (selectedItem is Outlook.MailItem)
{
// Cast selectedItem to MailItem.
Outlook.MailItem mailItem = selectedItem as Outlook.MailItem;
// Determine store of mailItem.
Outlook.Folder folder = mailItem.Parent as Outlook.Folder;
Outlook.Store store = folder.Store;
if (store.IsConversationEnabled == true)
{
// Obtain a Conversation object.
Outlook.Conversation conv = mailItem.GetConversation();
// Check for null Conversation.
if (conv != null)
{
// Obtain Table that contains rows
// for each item in Conversation.
Outlook.Table table = conv.GetTable();
Debug.WriteLine("Conversation Items Count: " + table.GetRowCount().ToString());
Debug.WriteLine("Conversation Items from Table:");
while (!table.EndOfTable)
{
Outlook.Row nextRow = table.GetNextRow();
Debug.WriteLine(nextRow["Subject"]
+ " Modified: "
+ nextRow["LastModificationTime"]);
}
Debug.WriteLine("Conversation Items from Root:");
// Obtain root items and enumerate Conversation.
Outlook.SimpleItems simpleItems = conv.GetRootItems();
foreach (object item in simpleItems)
{
// In this example, enumerate only MailItem type.
// Other types such as PostItem or MeetingItem
// can appear in Conversation.
if (item is Outlook.MailItem)
{
Outlook.MailItem mail = item as Outlook.MailItem;
Outlook.Folder inFolder = mail.Parent as Outlook.Folder;
string msg = mail.Subject
+ " in folder " + inFolder.Name;
Debug.WriteLine(msg);
}
// Call EnumerateConversation
// to access child nodes of root items.
EnumerateConversation(item, conv);
}
}
}
}
}
void EnumerateConversation(object item, Outlook.Conversation conversation)
{
Outlook.SimpleItems items = conversation.GetChildren(item);
if (items.Count > 0)
{
foreach (object myItem in items)
{
// In this example, enumerate only MailItem type.
// Other types such as PostItem or MeetingItem
// can appear in Conversation.
if (myItem is Outlook.MailItem)
{
Outlook.MailItem mailItem = myItem as Outlook.MailItem;
Outlook.Folder inFolder = mailItem.Parent as Outlook.Folder;
string msg = mailItem.Subject
+ " in folder " + inFolder.Name;
Debug.WriteLine(msg);
}
// Continue recursion.
EnumerateConversation(myItem, conversation);
}
}
}
In the sample code example, we get a selected MailItem object and then determine the store of the MailItem object by using the Store property of the Folder object. DemoConversation then checks whether the IsConversationEnabled property is true; if it is true, the code example gets Conversation object by using the GetConversation method. If the Conversation object is not a null reference, the example gets the associated Table object that contains each item in the conversation by using the GetTable method. The example then enumerates each item in the Table and calls EnumerateConversation on each item to access the child nodes of each item. EnumerateConversation takes a Conversation object and gets the child nodes by using the GetChildren(Object) method. EnumerateConversation is called recursively until there are no more child nodes. Each conversation item is then displayed to the user.

how to automatically trigger a link in outlook email using VSTO

I'm trying to programmatically click on a link which creates an email with predefined subject,to,cc,bcc and body content of the email.My requirement is, If I select an Outlook mail item and click on “Approve via mail” in my Addin, the code will search for hyperlink “Click here to Approve” in the mail body and Automatically click on the hyperlink.
The hyperlink “Click here to Approve” creates an email with predefined subject,to,cc,bcc and body content of the email.
I'm not sure how to do it with VSTO as all the other solutions suggest using JQuery and Javascript
Object selObject = this.Application.ActiveExplorer().Selection[1];
Outlook._MailItem eMail = (Outlook._MailItem)
this.Application.CreateItem(Outlook.OlItemType.olMailItem);
eMail = ((Outlook._MailItem)selObject);
if(eMail.HTMLBody.Contains("Approve"))
{
}
I'm not sure what I can write in the IF segment of the code.Please Suggest.
Outlook doesn't provide anything for opening hyperlinks. You can use the the following code (Process.Start) for opening them in the default web browser:
Process.Start("your_hyperlink");
Or just create a Mail item progrmmatically in Outlook based on the info where the Approve button was clicked.
Outlook.MailItem mail = null;
Outlook.Recipients mailRecipients = null;
Outlook.Recipient mailRecipient = null;
try
{
mail = OutlookApp.CreateItem(Outlook.OlItemType.olMailItem)
as Outlook.MailItem;
mail.Subject = "A programatically generated e-mail";
mailRecipients = mail.Recipients;
mailRecipient = mailRecipients.Add("Eugene Astafiev");
mailRecipient.Resolve();
if (mailRecipient.Resolved)
{
mail.Send();
}
else
{
System.Windows.Forms.MessageBox.Show(
"There is no such record in your address book.");
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message,
"An exception is occured in the code of add-in.");
}
finally
{
if (mailRecipient != null) Marshal.ReleaseComObject(mailRecipient);
if (mailRecipients != null) Marshal.ReleaseComObject(mailRecipients);
if (mail != null) Marshal.ReleaseComObject(mail);
}
Take a look at the following articles for more information and samples:
How to create and show a new Outlook mail item programmatically: C#, VB.NET
How To: Create and send an Outlook message programmatically
How To: Fill TO,CC and BCC fields in Outlook programmatically
How To: Create a new Outlook message based on a template

Use attachments from calendar items - Outlook - C#

I'm trying to use the attachments included in calendar items pulled progmatically.
I have a list of chosen calendar subject lines from a previous dialog box, and while the subject is transferring properly, the body isn't working well (another question altogether) but the attachments aren't working whatsoever.
Here's my foreach loop where the attachments are being placed into an Attachments array for use later:
string[] subjects = new string[dialog.chosen.Count];
string[] bodies = new string[dialog.chosen.Count];
Attachments[] attach = new Attachments[dialog.chosen.Count];
foreach (Outlook.AppointmentItem appt in rangeAppts)
{
foreach (string text in dialog.chosen)
{
if (text == appt.Subject)
{
subjects[i] = appt.Subject;
bodies[i] = Convert.ToString(appt.Body);
attach[i] = appt.Attachments;
i = i + 1;
}
}
}
And then here's where I actually call the method:
sendEmailTemplate(bodies[i], subject, to, "", attachment: attach[i]);
And then the method itself:
public void sendEmailTemplate(string body, string subject, string to, string cc , Attachments attachment = null)
{
Microsoft.Office.Interop.Outlook.Application oApp = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook._MailItem oMailItem = (Microsoft.Office.Interop.Outlook._MailItem)oApp.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);
oMailItem.HTMLBody = body;
oMailItem.Subject = subject;
try
{
oMailItem.Attachments.Add(attachment);
}
catch {}
oMailItem.To = to;
oMailItem.CC = cc;
oMailItem.Display(false);
oMailItem.Application.ActiveInspector().WindowState = Microsoft.Office.Interop.Outlook.OlWindowState.olNormalWindow;
}
I've tried several things, however when I actually go to send the e-mail, I end up getting:
Exception: Member not found. HRESULT: 0x80020003
And then I haven't been able to get anything else to work. The try/catch loop on the method is to prevent the above exception as I was getting that exception regardless of whether or not an attachment was present, and now attachments just aren't being added.
I'm using Interop that comes with Office along with C#. Winforms if that makes a difference.
MailItem.Attachments takes either a string (fully qualified file name), or another Outlook item (MailItem, ContactItem, etc.).
You cannot pass Attachments object as an argument. If you need to copy the attachments, loop through all attachments in the Attachments collection, call Attachment.SaveAsFile for each attachment, pass the file name to MailItem.Attachments.Add, delete thee temporary file.

EWS - Determine if an e-mail is a reply or has been forwarded

I am using the Exchange Web Services Managed API 2.2 to monitor users inboxes and need to determine if an e-mail is a new item, a reply or a forwarded message.
I have seen various articles on SO such as how to notice if a mail is a forwarded mail? and Is there a way to determine if a email is a reply/response using ews c#? which both help in their specific cases but I still cannot work out how to distinguish between a reply and a forwarded item.
In the first article an extra 5 bytes is added each time (forward or reply) so I don't know what the last action was.
The second article suggests using the InReplyTo however when I examine the property for forwarded e-mails it contains the original senders e-mail address (not null).
I have seen other articles such as this or this that suggest using extended properties to examine the values in PR_ICON_INDEX, PR_LAST_VERB_EXECUTED and PR_LAST_VERB_EXECUTION_TIME.
My code looks as follows but never returns a value for lastVerbExecuted
var lastVerbExecutedProperty = new ExtendedPropertyDefinition(4225, MapiPropertyType.Integer);
var response = service.BindToItems(newMails, new PropertySet(BasePropertySet.IdOnly, lastVerbExecutedProperty));
var items = response.Select(itemResponse => itemResponse.Item);
foreach (var item in items)
{
object lastVerb;
if (item.TryGetProperty(lastVerbExecutedProperty, out lastVerb))
{
// do something
}
}
PR_ICON_INDEX, PR_LAST_VERB_EXECUTED and PR_LAST_VERB_EXECUTION_TIME would only work to tell you if the recipient has acted on a message in their Inbox. Eg if the user had replied or forwarded a message in their inbox then these properties get set on the message in their Inbox. On the message that was responded to or forwarded these properties would not be set. I would suggest you use the In-Reply-To Transport header which should be set on any message that is replied to or forwarded, this should contain the internet messageid of the message that was replied to or forwarded eg.
FindItemsResults<Item> fiRs = service.FindItems(WellKnownFolderName.Inbox, new ItemView(10));
PropertySet fiRsPropSet = new PropertySet(BasePropertySet.FirstClassProperties);
ExtendedPropertyDefinition PR_TRANSPORT_MESSAGE_HEADERS = new ExtendedPropertyDefinition(0x007D, MapiPropertyType.String);
fiRsPropSet.Add(PR_TRANSPORT_MESSAGE_HEADERS);
service.LoadPropertiesForItems(fiRs.Items, fiRsPropSet);
foreach (Item itItem in fiRs)
{
Object TransportHeaderValue = null;
if(itItem.TryGetProperty(PR_TRANSPORT_MESSAGE_HEADERS,out TransportHeaderValue)) {
string[] stringSeparators = new string[] { "\r\n" };
String[] taArray = TransportHeaderValue.ToString().Split(stringSeparators, StringSplitOptions.None);
for (Int32 txCount = 0; txCount < taArray.Length; txCount++)
{
if (taArray[txCount].Length > 12)
{
if (taArray[txCount].Substring(0, 12).ToLower() == "in-reply-to:")
{
String OriginalId = taArray[txCount].Substring(13);
Console.WriteLine(OriginalId);
}
}
}
}
}
Apart from the Subject prefix that was discussed in the other link I don't know of any other proprieties that will differentiate between a reply or forward.
Cheers
Glen
The best way to rely is on the ResponeCode of Extended properties
Refer below scripts
private static int IsForwardOrReplyMail(ExchangeService service, EmailMessage messageToCheck)
{
try
{
// Create extended property definitions for PidTagLastVerbExecuted and PidTagLastVerbExecutionTime.
ExtendedPropertyDefinition PidTagLastVerbExecuted = new ExtendedPropertyDefinition(0x1081, MapiPropertyType.Integer);
ExtendedPropertyDefinition PidTagLastVerbExecutionTime = new ExtendedPropertyDefinition(0x1082, MapiPropertyType.SystemTime);
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.Subject, PidTagLastVerbExecutionTime, PidTagLastVerbExecuted);
messageToCheck = EmailMessage.Bind(service, messageToCheck.Id, propSet);
// Determine the last verb executed on the message and display output.
object responseType;
messageToCheck.TryGetProperty(PidTagLastVerbExecuted, out responseType);
if (responseType != null && ((Int32)responseType) == 104)
{
//FORWARD
return 104;
}
else if (responseType != null && ((Int32)responseType) == 102)
{
//REPLY
return 102;
}
}
catch (Exception)
{
return 0;
//throw new NotImplementedException();
}
}
To determine if it was a reply to a email, you can use the EmailMessage objects InReplyTo property, e.g:
EmailMessage mail = ((EmailMessage)Item.Bind(service, new ItemId(UniqueId)));
if (mail.InReplyTo == null)
return;
else
..your code

C# send email with Outlook - No attachment in Outbox

I have a program that is using Outlook to send messages with attachments. It is working ok, sending emails with attachments but in outbox there is no attachment in the message. When somebody receive the message the attachment is visible but in outbox not.
Here is some code:
Outlook.MailItem mail = (Outlook.MailItem)outlookApp.CreateItem(Outlook.OlItemType.olMailItem);
mail.BodyFormat = Outlook.OlBodyFormat.olFormatPlain;
int iAttachType = (int)Microsoft.Office.Interop.Outlook.OlAttachmentType.olByValue;
mail.Attachments.Add(Application.StartupPath+"/"+attachment, iAttachType, null, attachment);
mail.To = email;
mail.Subject = "Something";
mail.Body = "Some body";
mail.Send();
Before this I use:
private Outlook.Application outlookApp;
private Outlook._NameSpace outlookNameSpace;
private Outlook.MAPIFolder outbox;
and
outlookApp = new Outlook.Application();
outlookNameSpace = outlookApp.GetNamespace("MAPI");
outlookNameSpace.Logon(null, null, false, false);
outbox = outlookNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderOutbox);
My outlook program is connected with Microsoft Exchange Serwer. When I was using an application written in C++ it saved attachment in messages in outbox.
Thx for help!
You could be working with an old version of the outlook item.
This can happen if you keep references to your mail items, rec-patterns, inspectors and some other types [that I now forgot] longer than you need them.
Your reference will often point to the old version of the item and keeping it can also prevent you from getting a reference to the updated one (the one with the attachment), even when events (Folder.BeforeItemMove) are triggered.
Also, have you tried if mail.Save() would do anything for you?
This is what I use as soon as I am done with an item.
public static void NullAndRelease(object o)
{
if (o == null) {
return;
}
try {
int releaseResult = 0;
do {
releaseResult = System.Runtime.InteropServices.Marshal.ReleaseComObject(o);
} while (releaseResult >= 0);
} catch {
} finally {
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
The catch has no message and is not important in my case. It is there if someone would pass in a reference that leads to something other than a com object. You can also try FinalReleaseComObject(o).

Categories