I have the below code that I harvested from MSDN. The code seems to have been originally used in an Add In and as such I am having a problem with the this.Application.CreateItem(...) portion. What do I need to do differently to do this from my winform app?
private void AddAttachment(){
Outlook.MailItem mail =this.Application.CreateItem(Outlook.OlItemType.olMailItem)as Outlook.MailItem;
mail.Subject = "An attachment for you!";
OpenFileDialog attachment = new OpenFileDialog();
attachment.Title = "Select a file to send";
attachment.ShowDialog();
if (attachment.FileName.Length > 0)
{
mail.Attachments.Add(
attachment.FileName,
Outlook.OlAttachmentType.olByValue,
1,
attachment.FileName);
mail.Recipients.Add("Armando Pinto ");
((Outlook._MailItem)mail).Send();
}
Make sure you're in a VSTO project so you get the Office References loaded. If it's complaining up there, it's probably because it doesn't know what object you're trying to create.
Related
I have made small C# WFP application that sends emails with embedded images using C# and Outlook Interop. It seems that many mail clients reacts diffently to emails sent from this application compared to manually created emails where images are pasted directly in using CTRL+V.
I have tried to use OutlookSpy to compare the two emails, but I can't see any difference that could cause the different way the emails are being handled.
When an email sent from the C# application is received in an Outlook Application on an Iphone, the images are blank. It works just fine when the image is manually created and images are pasted in using CTRL+V.
1) How do I make sure that the emails sent from my application are handled the same way as when I manually create an email in Outlook and copy an image using CTRL+V?
If I can make this work, then it should be possible to make the images display correctly in Outlook for Iphone.
2) How does outlook handle an image when it is pasted in using CTRL+V? It seems that it uses Cid, the same way as I do in my application, but how does it refer to the image if it is not attached?
Here is the code for the sample application:
private void SendEmailButton_OnClick(object sender, RoutedEventArgs e)
{
SendMail();
}
public void SendMail()
{
var application = GetOutlookApplication();
MailItem newMail = (MailItem)application.CreateItem(OlItemType.olMailItem);
newMail.To = "!!!EnterValidEmailAddress!!!";
newMail.Subject = "Image test";
//Create image as embedded attachment
Attachment attachment1 = newMail.Attachments.Add(#"C:/SomeImage1.png", OlAttachmentType.olByValue);
string imageCid1 = "SomeImage_1";
//The property Accessor to be able to refer to the image from Email HTML Body using CID
attachment1.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001E", imageCid1);
//Set property Accesor to hide attachment
attachment1.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x7FFE000B", true);
//Refer the attachment using cid
newMail.HTMLBody = String.Format("<img src=\"cid:{1}\">", "google.dk", imageCid1);
newMail.Save();
newMail.Display();
}
public static OutlookApplication GetOutlookApplication()
{
// Start outlook process if it is not startet already
if (!IsOutlookRunning())
{
using (Process p = new Process())
{
p.StartInfo.FileName = "OUTLOOK.EXE";
p.Start();
if (!p.WaitForInputIdle(10000))
Thread.Sleep(5000);
}
}
// Start the outlook application (API)
OutlookApplication oApp = null;
if (Process.GetProcessesByName("OUTLOOK").Any())
{
try
{
oApp = Marshal.GetActiveObject("Outlook.Application") as OutlookApplication;
}
catch (System.Exception)
{
if (oApp == null)
oApp = new OutlookApplication();
}
return oApp;
}
oApp = new OutlookApplication();
return oApp;
}
private static bool IsOutlookRunning()
{
Process[] p = Process.GetProcessesByName("Outlook");
return p.Length != 0;
}
Make sure that you get a well-formed HTML markup finally. The following line of code just adds the <a> tag to the end of body string:
newMail.HTMLBody += String.Format("<img src=\"cid:{1}\">", "google.dk", imageCid1);
Instead, you need to find a right place for the image between the <body> and </body> tags.
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?
I need to save permanently some custom information inside an Outlook Mailitem and retrieve them back.
My case scenario is the following: I select an email in Outlook 2013 explorer, write inside that email some information, save it on my disk as .msg file, delete the email from the Inbox Outlook folder, open the .msg file as Outlook.MailItem and read that information in order to keep them or change them.
I'm using the Outlook.ItemProperties.Add() method to add a custom ItemProperty inside the selected MailItem.
When I get a MailItem from the .msg I'm not able to find that properties.
I've used OutlookSpy->Miscellaneous->OpenIMsgOnIstg function to check the .msg and I've noted that all properties are in the GetProps tab.
My question is: How can I read the properties?
Here is the code to write the properties and save the mail as .msg:
Outlook.Application outApp= new Outlook.Application();
Outlook.MailItem mail= null;
try { mail = (Outlook.MailItem)outApp.ActiveInspector().CurrentItem; }
catch {
if (outApp.ActiveExplorer().Selection.Count > 0)
mail = (Outlook.MailItem)outApp .ActiveExplorer().Selection[1];
else { // ERROR }
}
Outlook.ItemProperty prop01 = mail.ItemProperties.Add("MyProperty01", Outlook.OlUserPropertyType.olText);
prop01.Value = "hola";
Outlook.ItemProperty prop02 = mail.ItemProperties.Add("MyProperty02", Outlook.OlUserPropertyType.olNumber);
prop02.Value = 23;
mail.Save();
mail.SaveAs(#"C:\WorkSpace\mail.msg", Outlook.OlSaveAsType.olMSG);
if (mail != null) Marshal.ReleaseComObject(mail);
if (outlookObj != null) Marshal.ReleaseComObject(outApp );
Here is my code to read the properties from the .msg after I've deleted the email in Outlook:
Outlook.Application outApp= new Outlook.Application();
Outlook.MailItem msgMail=(Outlook.MailItem)outApp.CreateItem(Outlook.OlItemType.olMailItem);
msgMail = (Outlook.MailItem)outApp.Session.OpenSharedItem(#"C:\WorkSpace\mail.msg");
Outlook.ItemProperties mailProps = msgMail.ItemProperties;
Outlook.ItemProperty pr = mailProps["MyProperty01"]; // pr IS NULL
But OutlookSpy shows the properties are in the .msg file.
I have solved my problem following this bypassing solution.
Use Mailitem.PropertyAccessor.GetProperty and pass the DASL property name shown by OutlookSpy (I am its author).
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.)
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...