I have a mail (.msg), and i need to reply it. If user didn't set a signature for reply messages in Outlook, i'm creating default signature and appending it to a message body later.
public static MailItem CreateReplyMail(string mailPath, out string signature) {
signature = string.Empty;
try {
if(File.Exists(mailPath)) {
Application outlook = new Application();
var item = outlook.Session.OpenSharedItem(mailPath) as MailItem;
var replyMail = item.ReplyAll();
Inspector inspector = replyMail.GetInspector;
inspector.Activate();
return replyMail;
}
return null;
} catch(COMException e) {
//...
}
}
How can i verify existence signature in replying Outlook MailItem?
After inspector.Activate() in replyMail.Body i always have auto-generated text and signature, if user set it.
Use Document.Bookmarks.Exists("_MailAutoSig").
Related
I hope someone can help me out with this since when I drop a JSON test file in my rcv-folder the only result is that in the BizTalk console (in 'Running instances'), the message only states 'Queued (Awaiting processing)'. I am not sure where my issue is in the code.
I am supposed to receive a JSON which will contain some info and possibly multiple attachments (in Base64 format) and then send the mail out (with attachments in correct format, i.e. PDF, txt, xls) to a certain email-address. One of the requirements is to not use an orchestration. But I am stuck and have no idea what I am doing anymore. What makes this question different from others is that I have no orchestration in my solution. Everything will be processed in a custom send pipeline component.
The sendpipeline (in encode stage) does contain my custom component and also the MIME/SMIME encoder. I am using the SMTP-adapter.
I have created the custom pipeline component with a wizard and my initial plan was in the form below:
Receive the file (in JSON-format. It will be transformed into XML for further processing). This will all be taken care of in my rcv-pipeline and this step already works for me.
Pick out all the necessary variables from XML needed to send in the e-mail. These variables are the ones I want to show in the E-mail text. Not sure how to explain it better.
Pick out all the attachments in base64, loop through them, convert to 'regular files' and then attach them to the mail (with correct filenames, extension etc.)
The XML looks like below:
ArchiveobjectsListErrands
- ArchiveobjectErrand
* UUID (Here are the variables I need to show in the E-mail. The plain text, so to say)
- ArchiveobjectListPaper
- Attachments
* Name
* Extension
* Size
* Base64String (Base64 string which will be needed to be fetched (in GetAttachments) and then processed in (ProcessAttachments))
The code I have is below:
public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
{
// 1) Read file with XPathNavigator (https://learn.microsoft.com/en-us/dotnet/standard/data/xml/extract-xml-data-using-xpathnavigator)
XPathNavigator nav = ReadXmlFromMsgBox(pInMsg);
var outMsg = pContext.GetMessageFactory().CreateMessage();
outMsg.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);
// 2) Pick out the necessary vars that the registrator requires
GetRegistratorProperties(nav, pContext, outMsg);
// 3) Read attachments
var attachments = GetAttachments(pInMsg, nav);
// 4) Processa attachments
ProcessAttachments(pContext, outMsg, attachments);
// 5) Send message along for further processing in the send pipeline
return outMsg;
}
private void GetRegistratorProperties(XPathNavigator _nav, IPipelineContext _pContext, IBaseMessage _msg)
{
var bodyPart = _pContext.GetMessageFactory().CreateMessagePart();
bodyPart.ContentType = "text/application";
bodyPart.PartProperties.Write("EmailBodyText", "http://schemas.microsoft.com/BizTalk/2003/smtp-properties", "EmailBodyText.");
bodyPart.PartProperties.Write("Subject", "http://schemas.microsoft.com/BizTalk/2003/smtp-properties", "Registratorsubject - Create errand");
_msg.AddPart("Body", bodyPart, true); // True for body but false for attachments
}
private void ProcessAttachments(IPipelineContext _pContext, IBaseMessage _msg, IList<Attachment> _attachments)
{
var msgPart = _pContext.GetMessageFactory().CreateMessagePart();
//outMsg.Context = PipelineUtil.CloneMessageContext(_msg.Context);
int i = 0;
foreach (var item in _attachments)
{
msgPart.PartProperties.Write("FileName", "http://schemas.microsoft.com/BizTalk/2003/mime-properties", item.filnamn+item.extension);
msgPart.PartProperties.Write("ContentDescription", "http://schemas.microsoft.com/BizTalk/2003/mime-properties", item.contentType);
msgPart.Data = new MemoryStream(BytesFromBase64String(item.base64));
//bodyPart.Charset = "utf-8";
msgPart.ContentType = item.contentType;
//_pInMsg.AddPart("Attachment part " + i.ToString(), bodyPart, false);
_msg.AddPart("Attachment part " + i.ToString(), msgPart, false);
i++;
}
}
private IList<Attachment> GetAttachments(IBaseMessage pInMsg, XPathNavigator _nav)
{
XPathNodeIterator iterator = _nav.Select("Path to attachments in xml");
IList<Attachment> myList = new List<Attachment>();
while (iterator.MoveNext())
{
XPathNavigator node = iterator.Current;
Attachment atttachments = new Attachment();
atttachments.filenamne = node.SelectSingleNode("Name").Value;
atttachments.extension = node.SelectSingleNode("Extension").Value;
atttachments.contentType = node.SelectSingleNode("Mimetype").Value;
atttachments.base64 = node.SelectSingleNode("Base64String").Value;
myList.Add(atttachments);
}
return myList;
}
private XPathNavigator ReadXmlFromMsgBox(IBaseMessage pInMsg)
{
// Using XPathNavigator to avoid creating a XMLDoc in memory
Stream originalMessage = pInMsg.BodyPart.GetOriginalDataStream();
XPathNavigator _navigator = new XPathDocument(originalMessage).CreateNavigator();
return _navigator;
}
[Serializable]
private class FileStreamFactory : IStreamFactory
{
byte[] _data;
public FileStreamFactory(byte[] data)
{
_data = data;
}
public Stream CreateStream()
{
return new MemoryStream(_data);
}
}
private static byte[] BytesFromBase64String(string msg)
{
return Convert.FromBase64String(msg);
}
#endregion
}
I can show some example file of the XML if deemed necessary. I avoided it due to brevity and also since it is quite large.
I would greatly appreciate if anyone could help out with how the code is supposed to look to achieve what is needed, a mail with some text and attachments named correctly regarding filename and extension.
Body text and Attachments are just different segments in a MIME encoded email, usually a plain text one is the first one.
If it has a status of 'Queued (Awaiting processing)', then it sounds like either
the host instance that is expecting to process it is not in a running state. Fix: Start the host instance.
the send port is not in a Started sate. Fix: set the send port to Started
or the send port has a service window set on it. Fix: disable the service window.
I am working on an Outlook add-in to handle email attachments by placing them on a server and putting a URL in the email instead.
One problem is that after adding the URL to the end of the email body the user's cursor is reset to the start of the email.
A related problem is that I do not know where the cursor is in the text so I cannot insert my URL into the correct location.
Here is some code showing what I am doing, for simplicity the code is assuming the body is plain text.
private void MyAddIn_Startup(object sender, System.EventArgs e)
{
Application.ItemLoad += new Outlook.ApplicationEvents_11_ItemLoadEventHandler(Application_ItemLoad);
}
void Application_ItemLoad(object Item)
{
currentMailItem = Item as Outlook.MailItem;
((Outlook.ItemEvents_10_Event)currentMailItem).BeforeAttachmentAdd += new Outlook.ItemEvents_10_BeforeAttachmentAddEventHandler(ItemEvents_BeforeAttachmentAdd);
}
void ItemEvents_BeforeAttachmentAdd(Outlook.Attachment attachment, ref bool Cancel)
{
string url = "A URL";
if (currentMailItem.BodyFormat == Outlook.OlBodyFormat.olFormatHTML)
{
// code removed for clarity
}
else if (currentMailItem.BodyFormat == Outlook.OlBodyFormat.olFormatRichText)
{
// code removed for clarity
}
else
currentMailItem.Body += attachment.DisplayName + "<" + url + ">";
Cancel = true;
}
Use Application.ActiveInspector.WordEditor to retrieve the Word Document object. Perform all the changes using Word Object Model.
This seems to do what I want:
using Microsoft.Office.Interop.Word;
void ItemEvents_BeforeAttachmentAdd(Outlook.Attachment attachment, ref bool Cancel)
{
if (attachment.Type == Outlook.OlAttachmentType.olByValue)
{
string url = "A URL";
Document doc = currentMailItem.GetInspector.WordEditor;
Selection objSel = doc.Windows[1].Selection;
object missObj = Type.Missing;
doc.Hyperlinks.Add(objSel.Range, url, missObj, missObj, attachment.DisplayName, missObj);
Cancel = true;
}
}
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
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).
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.