How to Forward Current Message? - c#

I am developing an Outlook utility to forward the currently open message to a preset address.
This could be done with a macro but they are not as easily deployed to a user base.
I have created the UI for the add-in through Visual Studio ribbon design. I have a button on the ribbon to use for this process.
I am trying to put in button action similar to what is described here: forwarding MailItem Outlook Addinn issue.
How can I forward the current selection?
namespace OutlookAddIn2
{
public partial class Ribbon1
{
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
}
private void button1_Click(object sender, RibbonControlEventArgs e)
{
sendMail();
}
private void sendMail(Outlook.MailItem mail)
{
Outlook.Application Application = Globals.ThisAddIn.Application;
Outlook.MailItem newmail = Application.CreateItem(Outlook.OlItemType.olMailItem) as Outlook.MailItem;
newmail = mail.Forward();
newmail.Recipients.Add("____#example.com");
newmail.Send();
}
}
}

First of all, there is no need to create a new Outlook Application instance if you develop an add-in. Instead, you need to use the Application property which is available everywhere. See Global Access to Objects in Office Projects for more information.
In case if you deal with inspector windows you can use the following sequence of calls:
Application.ActiveInspector().CurrentItem
where the ActiveInspector method which returns the topmost Inspector object on the desktop. Use this method to access the Inspector object that the user is most likely to be viewing. For example:
Sub CloseItem()
Dim myinspector As Outlook.Inspector
Dim myItem As Outlook.MailItem
Set myinspector = Application.ActiveInspector
Set myItem = myinspector.CurrentItem
myItem.Close olSave
End Sub
But if you need to get the currently selected item in the Explorer window you can use the following sequence:
Application.ActiveExplorer().Selection[1]
where the ActiveExplorer method returns the topmost Explorer object on the desktop. This method is also useful for determining when there is no active explorer, so a new one can be opened.

The above code CloseItem() executed within an excel workbook rendered a run-time error 438, Object does not support this property or method. The reason I suspect is that there is no correct reference to the Outlook object model created.
I found a solution in code published by Wedge: Edit an open email from excel
I implemented the solution for the same purpose as above.
The adjusted code is as follows:
Sub CloseItemEdit()
Dim outlookApp As Outlook.Application
Set outlookApp = New Outlook.Application
Dim outlookInspector As Outlook.Inspector
Dim outlookMail As Outlook.MailItem
Set outlookInspector = outlookApp.ActiveInspector
If Not outlookInspector Is Nothing Then
If TypeOf outlookInspector.CurrentItem Is Outlook.MailItem Then
Set outlookMail = outlookInspector.CurrentItem
outlookMail.Close olSave
End If
End If
'Source: https://stackoverflow.com/questions/52596796/edit-an-open-email-from-excel
End Sub

Related

C# how to CC myself

I'm working on a VSTO project for Outlook. Very simple application with an icon on the ribbon. When user clicks on it, the selected email will be sent to the manager. It is working with the following code. But I want to add the sender as CC in the email. So whenever user clicks on it, the selected email will be sent to the manager and the user will be CC'd on it. So user will get a copy too. How can I CC the sender?
here is the code:
public partial class Ribbon1
{
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
}
private void button1_Click(object sender, RibbonControlEventArgs e)
{
Outlook.Application application = new Outlook.Application();
Outlook.NameSpace ns = application.GetNamespace("MAPI");
try
{
//get selected mail item
Object selectedObject = application.ActiveExplorer().Selection[1];
Outlook.MailItem selectedMail = (Outlook.MailItem)selectedObject;
//create message
Outlook.MailItem newMail = application.CreateItem(Outlook.OlItemType.olMailItem) as Outlook.MailItem;
newMail.To = "email#gmail.com";
newMail.CC = Outlook.Account;
newMail.Subject = "Subject Here";
newMail.Attachments.Add(selectedMail, Microsoft.Office.Interop.Outlook.OlAttachmentType.olEmbeddeditem);
newMail.Send();
selectedMail.Delete();
System.Windows.Forms.MessageBox.Show("Message has been sent! You have been CC'd.");
}
catch
{
System.Windows.Forms.MessageBox.Show("You must select a message to report.");
}
}
}
}
First of all, I've noticed the following line of code in the event handler:
Outlook.Application application = new Outlook.Application();
There is no need to create a new Outlook Application instance in the ribbon event handler if you develop VSTO based add-in for Outlook. Instead, you need to use the ThisAddIn.Application property. You can start writing your VSTO Add-in code in the ThisAddIn class. Visual Studio automatically generates this class in the ThisAddIn.vb (in Visual Basic) or ThisAddIn.cs (in C#) code file in your VSTO Add-in project. The Visual Studio Tools for Office runtime automatically instantiates this class for you when the Microsoft Office application loads your VSTO Add-in. To access the object model of the host application, use the Application field of the ThisAddIn class. This field returns an object that represents the current instance of the host application. See Program VSTO Add-ins for more information.
Use the Recipients.Add method to add new recipients to the email. For example, a raw sketch:
var recipient = Item.Recipients.Add(ThisAddIn.Application.GetNameSpace("MAPI").CurrentUser.Address);
recipient.Type = OlMailRecipientType.olCC;

OUTLOOK 2016 AddIn: Modified MailItem in InBox, can't be saved in a Outlook Custom Form (Read Layout)

I have a problem with development of a Office 365 Outlook Addin (Desktop).
I need to modify certain properties on a MailItem opened with a custom form ( Form designed in Outlook, exported as OFS file and imported in to Visual Studio AddIn project) but the call of method 'Save' on MailItem object
doesn't working, "Saved" property remain to "false" and when i close the inspector, Outlook prompt to save current item. No exception or error message raised on 'Save' call.
But if i try to call 'Save' to the same MailItem in the AddIn body, the message is saved.
I tried to write a simple test "addin" and i obtained the same result, but i can't understand this behaviour.
NB: with previous version of Outlook i haven't this issue.
Any idea?
Thanks so much!
Currently using VS2017, C#, .NET Framework 4.5, Interop library version 15.0
// ADD-IN BODY
private Outlook.Inspectors inspectors;
public static MailItem CurrentMailItem;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
inspectors = this.Application.Inspectors;
inspectors.NewInspector += Inspectors_NewInspector;
}
private void Inspectors_NewInspector(Inspector Inspector)
{
if (Inspector.CurrentItem is MailItem)
{
MailItem item = (MailItem)Inspector.CurrentItem;
item.MessageClass = "IPM.Note.MyReader";
item.Save();
bool saved = item.Saved;
Marshal.ReleaseComObject(item);
item = null;
}
}
// CUSTOM FORM:
private void FormRegion2_FormRegionShowing(object sender, System.EventArgs e)
{
// from this.OutlookItem
MailItem item = this.OutlookItem as MailItem;
item.Save();
bool saved = item.Saved; // <== SAVED=FALSE!
// from global variable (static)
ThisAddin.CurrentMailItem.Save();
saved = ThisAddin.CurrentMailItem.Saved; // <=== SAVED=FALSE!!!!
}
It seems you are using wrong event NewInspector to modify the message class. Have a look at this thread
I think it's a problem with the specific custom form that i've created, or a compatibility problem with Outlook 2016 (the same form working with Outlook 2013)
Steps to the resolution:
Create a new form for reader inspector with Outlook 20016.
Import new Form to Visual Studio 2017 project (there are some problem on import: it's necessary to add some registry key to specify Office installation path)
([see]https://social.msdn.microsoft.com/Forums/vstudio/en-US/3688eec8-2215-482c-ba5f-73f516ad26b8/unable-to-import-outlook-2016-form-region-ofs-into-visual-studio-2015-with-error-the?forum=vsto)
The new form is working and now i can modify and save mail item.
It's not the definitive solution, because now i must recreate a form with Outlook 2016 and i'm not sure that it's working with previous version of Office.
Moreover, the designer of Outlook 2016 have some problem with font size… i can't change font size to '8' for any label present in the form.

Open Specific MailItem in Outlook from C# via Mail.EntryID

Similar to this question,
Open Specific MailItem in Outlook from C# , In a C# VSTO application I'm trying to open an email in a new outlook window/inspector using the method GetFolderFromID and passing it's EntryID and StoreID.
Full code below:
Outlook.Application myApp = new Outlook.ApplicationClass();
Outlook.NameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
Outlook.MAPIFolder mySentBox = mapiNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
Outlook.MailItem myMail = ((Outlook.MailItem)mySentBox.Items[1]);
string guid = myMail.EntryID;
string folderStoreID = mySentBox.StoreID;
Outlook.MailItem getItem = (Outlook.MailItem)mapiNameSpace.GetItemFromID(guid, folderStoreID);
getItem.Display();
The below code only opens up the requested email in a new window when the email is already selected within outlook.
getItem.Display();
If not selected, the following error returns.
System.Runtime.InteropServices.ComException: 'A dialog box is open. Close it and try again'.
I've also attempted adding a new inspector & activating/displaying the email object via it with no success.
Kind regards
The error simply means a dialog box is open. Make sure there are no modal windows displayed and make sure you ever call MailItem.Display(true) to display items modally.

Opening multiple Outlook Window Send Email with C#

I need to open several Outlook windows previously populated with ticulo and email body for later user to inform the senders. I need to open several windows (I walk a grid to know how many windows).
I'm trying to do this with threads but an error message occurs saying: Outlook can not do this because the dialog box is open. Please close it and try again "
How to open multiple competing windows?
Test Call
private void button2_Click(object sender, EventArgs e)
{
int qtdEventos = dgvDescEvento.RowCount;
Thread[] Threads = new Thread[qtdEventos];
try
{
cEmail testeEmail = new cEmail();
for (int i = 0; i < qtdEventos; i++)
{
Threads[i] = new Thread(new ThreadStart(new cEmail().Monta));
}
foreach (Thread t in Threads)
{
t.Start();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace NavEventos.Class
{
class cEmail
{
private Outlook.Application outlookApp;
public cEmail()
{
outlookApp = new Outlook.Application();
}
public void Monta()
{
string pTitulo = "Title";
string pAssunto = "Body test";
Outlook._MailItem oMailItem = (Outlook._MailItem)outlookApp.CreateItem(Outlook.OlItemType.olMailItem);
Outlook.Inspector oInspector = oMailItem.GetInspector;
Outlook.Recipients oRecips = (Outlook.Recipients)oMailItem.Recipients;
#region MONTA ASSUNTO
oMailItem.Subject = pTitulo;
#endregion
#region MONTA CORPO DO E-MAIL
oMailItem.Body = pAssunto;
#endregion
oMailItem.Display(true);
}
}
}
You may not like this... but you shouldn't try. ;(
As you can see the Outlook COM interface is trying very hard to prevent you from doing this, it is one of the limitations of the outlook automation libraries that displaying a mail item is done in a modal kind of way.
There is good reason for this, your user is in your LOB application, then your code wants them to read an email in outlook, which you have done using the COM automation libraries for outlook. Now their outlook icon in the toolbar is flashing because a new email modal window has opened up, but this dialog may have opened up behind your current LOB app.
Now the user will need to switch context into Outlook to see the dialog and read the email.
If you can review your need to open these emails all at the same time then you and outlook com automation will get along just fine :)
Otherwise consider writing a plugin for Outlook and moving your email management routines into outlook itself. In there you can be very creative, sounds like you really need just a master - detail style of interface, like the main outlook browser, so you have a list of these emails and as the user clicks on them they are displayed in the preview inspector.
Maybe the solution is to use your logic to move these messages into a
specific folder in outlook, then use Outlook automation to make this
folder the current active window in outlook, then the user can decide
which emails they want to action or not.

Drag'n'drop one or more mails from Outlook to C# WPF application

I'm working on a windows client written in WPF with C# on .Net 3.5 Sp1, where a requirement is that data from emails received by clients can be stored in the database. Right now the easiest way to handle this is to copy and paste the text, subject, contact information and time received manually using an arthritis-inducing amount of ctrl-c/ctrl-v.
I thought that a simple way to handle this would be to allow the user to drag one or more emails from Outlook (they are all using Outlook 2007 currently) into the window, allowing my app to extract the necessary information and send it to the backend system for storage.
However, a few hours googling for information on this seem to indicate a shocking lack of information about this seemingly basic task. I would think that something like this would be useful in a lot of different settings, but all I've been able to find so far have been half-baked non-solutions.
Does anyone have any advice on how to do this? Since I am just going to read the mails and not send anything out or do anything evil, it would be nice with a solution that didn't involve the hated security pop ups, but anything beats not being able to do it at all.
Basically, if I could get a list of all the mail items that were selected, dragged and dropped from Outlook, I will be able to handle the rest myself!
Thanks!
Rune
I found a great article that should do exactly what you need to.
UPDATE
I was able to get the code in that article working in WPF with a little tweaking, below are the changes you need to make.
Change all references from System.Windows.Forms.IDataObject to System.Windows.IDataObject
In the OutlookDataObject constructor, change
FieldInfo innerDataField = this.underlyingDataObject.GetType().GetField("innerData", BindingFlags.NonPublic | BindingFlags.Instance);
To
FieldInfo innerDataField = this.underlyingDataObject.GetType().GetField("_innerData", BindingFlags.NonPublic | BindingFlags.Instance);
Change all DataFormats.GetFormat calls to DataFormats.GetDataFormat
Change the SetData implementation from
public void SetData(string format, bool autoConvert, object data)
{
this.underlyingDataObject.SetData(format, autoConvert, data);
}
TO
public void SetData(string format, object data, bool autoConvert)
{
this.underlyingDataObject.SetData(format, data, autoConvert);
}
With those changes, I was able to get it to save the messages to files as the article did. Sorry for the formatting, but numbered/bulleted lists don't work well with code snippets.
I found a lot of solutions suggesting you use the “FileGroupDescriptor” for all the file names and the “FileContents” on the DragEventArgs object to retrieve the data of each file. The “FileGroupDescriptor” works fine for the email message names, but “FileContents” returns a null because the implementation of the IDataObject in .Net cannot handle the IStorage object that is returned by COM.
David Ewen has a great explanation, excellent sample and code download that works great at http://www.codeproject.com/KB/office/outlook_drag_drop_in_cs.aspx.
In your Xaml you need to set up your Event:
<TextBlock
Name="myTextBlock"
Text="Drag something into here"
AllowDrop="True"
DragDrop.Drop="myTextBlock_Drop"
/>
Once you have Set AllowDrop = True and Set you drop event then go to the code behind and set up your event:
private void myTextBlock_Drop(object sender, DragEventArgs e)
{
// Mark the event as handled, so TextBox's native Drop handler is not called.
e.Handled = true;
Stream sr;
//Explorer
if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
//Do somthing
//Email Message Subject
if (e.Data.GetDataPresent("FileGroupDescriptor"))
{
sr = e.Data.GetData("FileGroupDescriptor") as Stream;
StreamReader sr = new StreamReader(sr2);//new StreamReader(strPath, Encoding.Default);
//Message Subject
string strFullString = sr.ReadToEnd();
}
}
If you wish to break it down further you can use:
FILEDESCRIPTOR or FILECONTENTS as outline in the following article
your other option is to tie into outlooks MS Office Primary Interop Assemblies and break the message apart that way.
I think Shell Style Drag and Drop in .NET (WPF and WinForms) can help you. Once you can respond to drag drop using the COM Interfaces, you should be able to get the data out of outlook.
I assume that you have an Exchange server running behind Outlook.
What you can do is to retrieve the mail from the Exchange server and store its location in your database based on the mail's EntryID and StoreID. Here's a VB.Net snippet:
Imports Microsoft.Office.Interop
Public Class OutlookClientHandler
Private _application As Outlook.Application
Private _namespace As Outlook.NameSpace
Public Sub New()
If Process.GetProcessesByName("outlook".ToLower).Length > 0 Then
_application = New Outlook.Application
Else
Dim startInfo As ProcessStartInfo = New ProcessStartInfo("outlook.exe")
startInfo.WindowStyle = ProcessWindowStyle.Minimized
Process.Start(startInfo)
_application = New Outlook.Application
End If
End Sub
' Retrieves the specified e-mail from Outlook/Exchange via the MAPI
Public Function GetMailItem(ByVal entryID as String, ByVal storeID as String) As Outlook.MailItem
_namespace = _application.GetNamespace("MAPI")
Dim item As Outlook.MailItem
Try
item = _namespace.GetItemFromID(entryID, storeID)
Catch comex As COMException
item = Nothing ' Fugly, e-mail wasn't found!
End Try
Return item
End Function
End Class
I guess you are comfortable with using the MAPI, otherwise you can read up here:
http://msdn.microsoft.com/en-us/library/cc765775(v=office.12).aspx
To retrieve the selected e-mails from outlook:
Public Function GetSelectedItems() As List(Of Object)
Dim items As List(Of Object) = New List(Of Object)
For Each item As Object In _application.ActiveExplorer().Selection
items.Add(item)
Next
Return items
End Function
After you've retrieved the e-mails from Outlook you can just push them into your database! Save their EntryID and StoreID (you might want to store their parent's (the folder's) EntryID and StoreID as well).

Categories