I am editing an email and send it to the recipient. But i also want to save the original mail in the sent folder. But if i move the mailobject to the folder the mail is still editable.
This is how i move the mail:
private void CopyMailToSent(Outlook.MailItem originalMail)
{
var folder = originalMail.SaveSentMessageFolder;
originalMail.Move(folder);
}
Can i set the mailobject to readonly or faking the send?
Firstly, Outlook Object Model would not let you set the MailItem.Sent property at all. On the MAPI level, the MSGFLAG_UNSENT bit in the PR_MESSAGE_FLAGS property can only be set before the message is saved for the very first time.
The only OOM workaround I am aware of is to create a post item (it is created in the sent state), set its message class to "IPM.Note", save it, release it, reopen by the entry id (it will be now MailItem in the sent state), reset the icon using PropertyAccessor, set some sender properties (OOM won't let you set all of them).
If using Redemption (I am its author) is an option, it will let you set the Sent property as well as the sender related properties, plus add recipients without having to resolve them.
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 "Joe The User", "joe#domain.demo", "SMTP", olTo
msg.Sender = MySession.CurrentUser
msg.SentOnBehalfOf = MySession.CurrentUser
msg.subject = "Test sent message"
msg.Body = "test body"
msg.UnRead = false
msg.SentOn = Now
msg.ReceivedTime = Now
msg.Save
I couldn't solve the problem but i did workaround which works fine for me.
I hope it's ok to post this here even it's not right the solution. If not, sorry i will delete it.
My workaround is saving the orignal mail as ".msg" file and then add it to the mail in the sent folder.
Then it looks like this:
This is the code:
private void SendMail(Outlook.Mailitem mail)
{
mail.SaveAs(tempDirectory + #"originalMail.msg");
var folder = mail.SaveSentMessageFolder;
ChangeMailSubject(mail);
ChangeMailText(mail);
mail.Send();
folder.Items.ItemAdd += new Outlook.ItemsEvents_ItemAddEventHandler((sender) => AttachOriginalMail(sender);
}
private void AttachOriginalMail(object sender)
{
var mail = (Outlook.MailItem) sender;
mail.Attachments.Add(tempDirectory + #"originalMail.msg");
mail.Save();
}
Related
So i need to get informations such as :
Sender mail address (to later get his Domain profile informations)
Mail subject (which should be the "filepath" minus the "msg" extension anyway).
And then, replying to it just like i would push "ReplyAll" button in Outlook. So the reply needs to get the usual Headers such as "From : ....", "To : ...", "Cc : ..." and so on.
All i need is to change its subject, and delete the address depending on the "FromAddress" of the user that will push the button
I've read a bit here and there, and people are talking about a MailItem, but there's no informations about HOW to get this item or how to build it from a .msg file.
What i have to do comes after a specific user action.
The user is supposed to Drag&Drop the mail into a panel, from there i get its local path.
Thanks for your time !
Edit#1
I managed to find out to get informations and to set a .msg file to a MailItem :
Outlook.Application appOutlook = new Outlook.Application();
var email = (Outlook.MailItem)appOutlook.Session.OpenSharedItem(filepath);
string getCC = "";
string getFrom = ""; // From is never null
string getTo = "";
string getSubject = "";
bool lengthCC = email.CC.HasValue();
bool lengthTo = email.To.HasValue();
bool lengthSubject = email.Subject.HasValue();
if (lengthCC)
{
getCC = email.CC.ToString();
}
// and so on...
//
// Display it in MessageBox to confirm test succeeded :
MessageBox.Show("CC : " + getCC +
"\nFrom : " + getFrom +
"\nTo : " + getTo +
"\nSubject : " + getSubject);
email.Close(Outlook.OlInspectorClose.olDiscard);
Now i just need to build the ReplyAll Body and add headers manually myself i guess...
Edit#2
No need to rewrite Headers apparently, doing so :
Outlook._MailItem reply = email.ReplyAll();
reply.To = getFrom;
reply.CC = getCC;
reply.Body = "SomeReplyMessage" + reply.Body;
reply.Send();
Marshal.ReleaseComObject(appOutlook);
Marshal.ReleaseComObject(email);
Marshal.ReleaseComObject(reply);
But it erased the separator above the original message, i'll find a way to re-add it !!!
Edit#3
And there it is, the so-called "separator" wasn't displaying, because i wasn't re-stating an HTML Body !
So, to keep it you can do this :
reply.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
string ReplyMessageBody = String.Format("AddSome<br>HTMLCode<br>ThereAndHere<br>ButFinishWith : BodyTag</body>");
reply.HTMLBody = ReplyMessageBody + reply.HTMLBody;
Or simpler if you don't need your reply to be an HTML one :
reply.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
reply.HTMLBody = "AddSomeReplyMessage" + reply.HTMLBody;
Outlook does not work directly wit MSG files - when you call CreateFromTemplate or even OpenSharedItem, Outlook creates a new item in its default store and imports the MSG or OFT file. It does not expose anything that would you let you figure out that the message came from a file; the item is indistinguishable from an item created directly using CreateItem or MAPIFolder.Items.Add.
See edits on original question for answer !
I am trying to have my application to open the Outlook meeting window with some pre-populated fields.
I have found that this question was already asked here.
However, the code provided in the answer(which works fine) doesn't open the meeting window but the appointement window. Those are two different things that are handled differently in Outlook and what I need is indeed the meeting window.
Is there any way to achieve this or do I absolutely have to open the appointement window first and then invite people to turn it into a meeting?
Create an appointment just as in the other question, but then set the MeetingStatus property of the appointment.
Microsoft.Office.Interop.Outlook.Application outlookApplication = new Microsoft.Office.Interop.Outlook.Application(); ;
Microsoft.Office.Interop.Outlook.AppointmentItem appointmentItem = (Microsoft.Office.Interop.Outlook.AppointmentItem)outlookApplication.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olAppointmentItem);
// This line was added
appointmentItem.MeetingStatus = Microsoft.Office.Interop.Outlook.OlMeetingStatus.olMeeting;
appointmentItem.Subject = "Meeting Subject";
appointmentItem.Body = "The body of the meeting";
appointmentItem.Location = "Room #1";
appointmentItem.Start = DateTime.Now;
appointmentItem.Recipients.Add("test#test.com");
appointmentItem.End = DateTime.Now.AddHours(1);
appointmentItem.ReminderSet = true;
appointmentItem.ReminderMinutesBeforeStart = 15;
appointmentItem.Importance = Microsoft.Office.Interop.Outlook.OlImportance.olImportanceHigh;
appointmentItem.BusyStatus = Microsoft.Office.Interop.Outlook.OlBusyStatus.olBusy;
appointmentItem.Recipients.ResolveAll();
appointmentItem.Display(true);
One more note to NineBerries good solution, because I had an issue here:
The line
appointmentItem.Recipients.ResolveAll();
is necessary if you have optional attendees in the meeting.
Otherwise they will be reset to "required" even if you set
recipient.Type = Microsoft.Office.Interop.Outlook.OlMeetingRecipientType.olOptional;
before, which is due to "late auto-resolving" of names in Outlook (or so it seems).
I just started to dabble into using Microsoft.Office.Interop.Outlook. I was able to successfully send an email using the bit of code below.
public void Send()
{
try
{
Outlook._Application _app = new Outlook.ApplicationClass();
var test = _app.CreateItem(Outlook.OlItemType.olMailItem);
Outlook.MailItem mail = (Outlook.MailItem) _app.CreateItem(Outlook.OlItemType.olMailItem);
mail.To = "testemail#fakeaddress.com";
mail.Subject = "Test Outlook Subject";
mail.Body = "Test Outlook Body";
mail.Importance = Outlook.OlImportance.olImportanceNormal;
((Outlook.MailItem) mail).Send();
}
catch
{
Notification.Notice("Error");
}
}
I would like to have a Validate() function before the try/catch such that it'll check to see if there's a valid outlook account enabled. May I ask does anyone know how I can check if any outlook accounts are setup?
I tried this
public bool validate()
{
Outlook._Application _app = new Outlook.ApplicationClass();
Outlook.Accounts accounts = _app.Session.Accounts;
return accounts.Count > 0;
}
But accounts.Count returned 1 even after I removed my outlook account.
There will always be at least one account - the store. Otherwise Outlook won't run. But even if there are mail accounts, how would you know whether they are configured appropriately? Unless you take over the message submission, there is no way for you to know ahead of time.
UPDATE: Loop through the Namespace.Accounts collection and look for accounts with Account.AccountType == olExchange ,olImap,olPop3, olHttp. Keep in mind that OOM only list mail accounts, not store or address book.
If you were using Extended MAPI (C++ or Delphi), you could use IOlkAccountManager::EnumerateAccounts(CLSID_OlkMail, ...) (you can play with that interface in OutlookSpy (I am its author) - click IOlkAccountManager button). If Extended MAPI is not an option, Redemption (I am also its author) exposes the RDOAccounts object; its GetOrder(acMail) method will return all mail accounts. You'll just need to check if the returned collection has any elements.
I'm new to office addins. I'm an MVC programmer but this project has been dumped on me as no one else wants to do it. I need to create an outlook addin that will forward all email data to a service where communications can be tracked by a recruitment system.
I am using
Application.ItemSend += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_ItemSendEventHandler(saveEmail);
where I then cast the email into a Outlook.MailItem. The problem is I see no way of getting the from and to email addresses. All it gives me is the name of the people. Am I missing something?
So far the best solution I can think of is to save the msg as a .msg file. Forward that to my service and then user a parser I found to convert it to HTML.
Any suggestions?
To access the recipients, loop through MailItem.Recipients collection and access Recipient.Name and Recipient.Address properties.
Sender related properties are not yet set by the time ItemSend event fires - the earliest you can access sender properties is when Items.ItemAdd event fires on the Sent Items folder (retrieve it using Namespace.GetDefaultFolder).
You can read the MailItem.SendUsingAccount. If it is null, use the first Account from the Namespace.Acounts collection. You can then use Account.Recipient object.
Keep in mind that you should not blindly cast outgoing items to MailItem objects - you can also have MeetingItem and TaskRequestItem objects.
OK using the info given to me by Dmitry Streblechenko and some other info I just looked up here is my solution so far.
In the ItemSend event I first make sure that sent email is moved to the default sent items folder. I'm testing outlook using gmail so normally these will go elsewhere. sentMailItems is made as a class field as apparently it will get garbage collected if its just declared inside the Startup function (Something quite odd to me an MVC programmer :) ).
I' will test this on exchange when I get back to office an hopefully all goes well.
public partial class ThisAddIn
{
public Outlook.Items sentMailItems;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Application.ItemSend += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_ItemSendEventHandler(ItemSend);
sentMailItems = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail).Items;
sentMailItems.ItemAdd += new Outlook.ItemsEvents_ItemAddEventHandler(Items_ItemAdd);
}
void Items_ItemAdd(object item)
{
MessageBox.Show(((Outlook.MailItem)item).Subject);
var msg = Item as Outlook.MailItem;
string from = msg.SenderEmailAddress;
string allRecip = "";
foreach (Outlook.Recipient recip in msg.Recipients)
{
allRecip += "," + recip.Address;
}
}
private void ItemSend(object Item, ref bool Cancel)
{
if (!(Item is Outlook.MailItem))
return;
var msg = Item as Outlook.MailItem;
msg.DeleteAfterSubmit = false; // force storage to sent items folder (ignore user options)
Outlook.Folder sentFolder = this.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail) as Outlook.Folder;
if (sentFolder != null)
msg.SaveSentMessageFolder = sentFolder; // override the default sent items location
msg.Save();
}
//Other auto gen code here....
}
I'm having a slight problem with adding text to forwarding emails. This is my current code:
private void ForwardFunction(Outlook.MailItem email)
{
Outlook.MailItem forwardEmail = ((Outlook._MailItem)email).Forward();
Outlook.Inspector forwardInsp = forwardEmail.GetInspector;
Word.Document forwardDoc = forwardInsp.WordEditor;
Word.Range forwardRange = forwardDoc.Range(0,1);
string forwardText = "This is some text";
forwardRange.Text = forwardText + forwardRange.text
newEmail.Recipients.Add("myemail");
forwardEmail.Save();
((Outlook._MailItem)forwardEmail).Send();
}
I've gone through it and it does add the text to the range, but when I receive the forwarded email it doesn't contain any of the additional text. I've used similar code to edit current emails that the user is editing (New, Replies/Forwards, InlineResponses) with success, but the email being passed to the function is the currently selected email in the inbox. Not sure if this matters, maybe because it's not being edited by the user.
I couldn't find a specific way to add new text to a programmatically forwarded email.
For anyone else interested in this, I ended up using the .HTMLBody. It seems that using the .GetInspector either gets the inspector of the _email instead of fEmail and you can't edit it or it gets the correct inspector but it can't edit it. Either way, using the .HTMLBody seems to get around it.
Outlook.MailItem fEmail = ((Outlook._MailItem)_email).Forward();
string forwardText;
forwardText = "class=MsoNormal>";
forwardText += "This is my forwarded message";
forwardText += "Bonus hyper link <a href='" + hyperlinkText + "'>" + hyperlinkText + "</a>";
var regex = new Regex(Regex.Escape("class=MsoNormal>"));
fEmail.HTMLBody = regex.Replace(fEmail.HTMLBody, forwardText, 1);
fEmail.Save();
fEmail.AutoForwarded = true;
((Outlook._MailItem)fEmail).Send();