How to update HTMLBody of the MailItem - c#

I`m trying to create outlook mails from templates, slightly edit them and then show to user so he can send that mail.
There is no problem in creation of the mail and displaying it. But when I`m trying to read (or edit) HTMLBody of the mail there is a error:
Operation aborted (Exception from HRESULT: 0x80004004 (E_ABORT))
Here is my code:
using Outlook = Microsoft.Office.Interop.Outlook;
...
try
{
var app = new Outlook.Application();
Outlook.MailItem mailItem = app.CreateItemFromTemplate("C:\\Test\\template.oft");
var body = mailItem.HTMLBody; //Here is the exception
mailItem.HTMLBody = body.Replace("#firstname", "Test Testy");
mailItem.To = message.EmailAddress;
mailItem.Display(mailItem);
}
catch (Exception ex)
{
...
}
Added example project on github.

var app = new Outlook.Application();
Before creating a new instance of the Outlook Application class I'd suggest checking whether it is already run and get the running instance then:
if (Process.GetProcessesByName("OUTLOOK").Any())
app = System.Runtime.InteropServices.Marshal.GetActiveObject("Outlook.Application");
Outlook is a singleton. You can't run multiple instances at the same time.
Also I'd suggest saving the newvly created item before accessing the HTMLBody property value:
Outlook.MailItem mailItem = app.CreateItemFromTemplate("C:\\Test\\template.oft");
mailIte.Save();
var body = mailItem.HTMLBody; //Here is the exception
Finally, the Display method doesn't take a MailItem instance. Instead, you can pass true to get the inspector shown as a modal window or just omit the parameter (false is used by default).
BTW Where and when do you run the code?

Related

Changing the sender address to default server in Outlook Object Mail

I have the following code to send emails automatically when looping through data retrieved from db:
public void sendMailV2(string subject, string body, string emailAddress)
{
// Create the Outlook application.
Outlook.Application oApp = new Outlook.Application();
// Get the NameSpace and Logon information.
Outlook.NameSpace oNS = oApp.GetNamespace("mapi");
// Log on by using a dialog box to choose the profile.
oNS.Logon(Missing.Value, Missing.Value, true, true);
// Alternate logon method that uses a specific profile.
// TODO: If you use this logon method,
// change the profile name to an appropriate value.
//oNS.Logon("YourValidProfile", Missing.Value, false, true);
// Create a new mail item.
Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
// Set the subject.
oMsg.Subject = subject;
// Set HTMLBody.
oMsg.HTMLBody = body;
// Add a recipient.
Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients;
// TODO: Change the recipient in the next line if necessary.
Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add(emailAddress);
oRecip.Resolve();
// Send.
oMsg.Send();
// Log off.
oNS.Logoff();
// Clean up.
oRecip = null;
oRecips = null;
oMsg = null;
oNS = null;
oApp = null;
}
However, I want the emails to be sent from the server, not my own outlook. I have the username and password for the server(someserver#serving.com) but I can't figure out how and where to implement them.
I would appreciate any help.
First of all, there is no need to create a new Application instance if you need to send multiple emails. You may consider moving the following lines of code outside of the method and create the Application instance at the global scope.
// Create the Outlook application.
Outlook.Application oApp = new Outlook.Application();
If you have got another accounts configured in Outlook, you can use the SendUsingAccount property of the MailItem class which allows to set an Account object that represents the account under which the MailItem is to be sent.
If you don't have the required account configured in Outlook you may consider using the BCL classes for getting the job done. See How to send email from C# for more information.

Zipping outlook attachment on the fly

I'm developing a Visual Studio extension that adds a command to VS to compose a message in Outlook with an attachment. The attachment is simple .csv file that is also produced by the extension.
So when user fires the command, outlook opens a window with an email already composed and attachment added. The user might just click send.
Now I've been asked to add possibility to send those logs compressed with zip. I would like to compose a message with an attachment already compressed, but I don't want any temporary .zip files retained after message is sent (or cancelled). How can I achieve this?
My code that composes the message and opens Outlook window:
using Microsoft.Office.Interop.Outlook;
...
private static bool TrySendMethod1(string subject, string toAddr, string body, string logPath)
{
try
{
Application app = new Application();
MailItem mailItem = app.CreateItem(OlItemType.olMailItem);
mailItem.Subject = subject;
mailItem.To = toAddr;
mailItem.Body = body;
if (logPath != null) mailItem.Attachments.Add(logPath);
mailItem.Importance = OlImportance.olImportanceNormal;
mailItem.Display(false);
return true;
}
catch (System.Exception e)
{
return false;
}
}
update
Once the email is composed, an outlook window with a composed message is displayed (it has the attachment already set). Now, the user might just send it, cancel it or whatever. He might even leave the window opened for hours (although this is not common) and then send it (even after VS has been closed). Again, i don't want any temporary archives to exist on the disk after the message is sent or cancelled.
I added full method that sends the email. It's not much more, but this method is just invoked when user selects a new Visual Studio command that my extension adds to it (tools -> send TFS logs -> from this month). There just an additional method between button handler and it simply sets some parameters for the one presented here (sets the subject, logPath and so on...)
If it's not possible, then I can also accept such an answer.
You can compress a file using this:
public static void Compress(FileInfo fileToCompress, string compressedFileName)
{
using (FileStream originalFileStream = fileToCompress.OpenRead())
{
using (FileStream compressedFileStream = File.Create(compressedFileName)
{
using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress))
{
originalFileStream.CopyTo(compressionStream);
}
}
}
}
Modified from: http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx
For deleting the file afterwards you can attach to the MailItem.Unload Event.
This event occurs after the Close event for the Outlook item occurs,
but before the Outlook item is unloaded from memory, allowing an
add-in to release any resources related to the object. Although the
event occurs before the Outlook item is unloaded from memory, this
event cannot be canceled.
Source: http://msdn.microsoft.com/en-us/library/office/ff868564(v=office.15).aspx
Then you TrySendMethod1 could look like this
private static bool TrySendMethod1(string subject, string toAddr, string body, string logPath)
{
try
{
Application app = new Application();
MailItem mailItem = app.CreateItem(OlItemType.olMailItem);
mailItem.Subject = subject;
mailItem.To = toAddr;
mailItem.Body = body;
string compressedFileName = logpath + ".gz";
CompressedStack(logpath, compressedFileName);
if (logPath != null) mailItem.Attachments.Add( compressedFileName );
mailItem.Importance = OlImportance.olImportanceNormal;
mailItem.Display(false);
mailItem.Unload += (e) => {File.Delete(compressedFileName);};
return true;
}
catch (System.Exception e)
{
return false;
}
}
Exception handling for the File.Delete is missing, and I am not sure 100% certaing about the signature of the Unload event, but have a try and let us know.
This will NOT handle the case where Visual Studio is closed BEFORE the mail is sent! (I think that might not even be possible.)

Not setting the property of incoming mails in MS Outlook 2010

I am setting the property (for making them As Read and with High Importance) of the mail those are coming to the MS Outlook 2010 inbox using below code -
Microsoft.Office.Interop.Outlook.Application myApp = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
Microsoft.Office.Interop.Outlook.MAPIFolder myInbox = mapiNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
int i = myInbox.Items.Count;
((Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[i]).UnRead = false;
((Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[i]).Importance = OlImportance.olImportanceHigh;
This works fine when only one mail comes at a time (I can see the mail as Read and with High Importance) after the code execution but when three or four mails coming at a time then it set the property of only one mail not for all the three or four mails.
Please suggest.
Remember to save the message after setting any property.
Most importantly, your code uses multiple dot notation - for each ".", you get back a brand new COM object, so you end up setting Importance property on an object different from the one used to set the UnRead property.
int i = myInbox.Items.Count;
MailItem msg = (Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[i];
msg.UnRead = false;
msg.Importance = OlImportance.
msg.Save();
Another problem is that you assume that the last item in the Items collection is the latest one. This is not generally true. As cremor suggested, use Items.ItemAdd event, but still do not forget to save the message.
You can use the ItemAdd event of the Items property of the folder:
Items inboxItems = myInbox.Items;
inboxItems.ItemAdd += HandleItemAdded;
private void HandleItemAdded(object item)
{
MailItem mail = item as MailItem;
if (mail == null) { return; }
mail.UnRead = false;
mail.Importance = OlImportance.olImportanceHigh;
}

Create multiple Outlook emails from C#

I'm new to C#. I've found how to create an outlook email from C#:
// Create a new MailItem.
Outlook._MailItem oMsg1;
oMsg1 = oApp.CreateItem(Outlook.OlItemType.olMailItem);
oMsg1.To = "amine#gmail.com";
oMsg1.Subject = "Test Subject";
oMsg1.Body = "test Body";
Outlook.Attachments oAttachs1 = oMsg1.Attachments;
// Add an attachment
string sSource1 = "C:\\testFile.xls";
Outlook.Attachment oAttach1;
oAttach1 = oAttachs1.Add(sSource1);
oMsg1.Display(true);
oApp = null;
oMsg1 = null;
oAttach1 = null;
oAttachs1 = null;
But I want to create multiple emails at the same time. So Outlook will display multiple email windows.
I tried a for loop to create multiple mailItem but this didn't work. Outlook displays only the first email.
Any idea ? Thanks!
Use oMsg1.Display(false);
When set to True, oMsg1.Display(true) means Outlook creates a 'Modal' window, meaning it freezes that particular email until it is sent or discarded.

Create/Open existing msg from path to new Outlook.MailItem in c#

Hello I'd like to create a Outlook.MailItem ( I believe ) from an existing one located on disk. I have the path stored in a string, and would like to access to save the body and attachments from it.
I can't seem to figure out how to open it in c# and access it.
currently I have something along the lines of
where fl evaluates out to something like "C:\users\msgs\email.msg"
Thanks for the time
Outlook.Application app = new Outlook.Application();
try
{
foreach (String fl in Directory.GetFiles(docInfo.LocalPath + _preprocessorDirectory))
{
if (Regex.IsMatch(fl.Trim(), _regex, RegexOptions.IgnoreCase))
{
Outlook.MailItem email = new Outlook.MailItem(fl);
SaveAttachments(email);
SaveBody(email);
}
}
}
catch (Exception ex)
{
logger.Error("Error in Process for document " + docInfo.OriginalPath, ex);
callback.Invoke(docInfo, false);
}
return false;
To open an item in outlook try:
var email = (Outlook.MailItem)app.Session.OpenSharedItem(fl)
From there, you can access the Attachments property and Body property as well.
Also, as I mentioned in my comment if the Regex.IsMatch is to determing the file extension, use Path.GetExtension() instead
I used this NuGet package: https://www.nuget.org/packages/MSGReader/
Seems to work fine. I prefer it to the MS OutlookApi library because it doesn't require Outlook to be installed.
I appreciate that it won't create instances of MailItem, as you have asked for in your question - but it will enable you to extract save the individual attachments and the body...

Categories

Resources