.Net VSTO trasformare una email di tipo msg in EML per le pec in VB

Articolo sulla programmazione office, in particolare sul programma di posta elettronica Outlook, per estenderlo con funzionalità sulla gestione della PEC tramite componenti aggiuntivi.

il
Sviluppatore Microsoft .Net, Collaboratore di IProgrammatori

 In questo articolo vedremo come convertire una email nel formato Outlook 2016 che ha l’estensione “.msg” nel formato universale per altri client email di tipo “.eml”.
Inoltre si sperimenterà la conversione su una email di tipo “PEC” con all’interno del messaggio un allegato, fornendo così al lettore interessanti spunti per realizzare programmi o gestire i propri progetti .Net nel modo migliore.
Il tutto verrà illustrato con i linguaggi di programmazione più usati per la tecnologia .Net in particolare con il linguaggio VB.Net e C#

Stesura del codice


Si crea un nuovo progetto di tipo VSTO con Visual Studio 2017 community o altre versione.
Nella creazione del progetto, selezionare il linguaggio di proprio interesse, nelle varie sotto voci, fare click sulla voce “Office/Sharepoint” e nel sotto menu selezionare “Componenti Aggiuntivi” a questo punto, nella parte dei modelli (parte centrale) selezionare il modello di tipo “Componente aggiuntivo per Outlook 201x” dove la X sta indicando la versione (2016 o 2013).
Facciamo click sulla classe (o file) denominato “ThisAddin” presente per i due linguaggi.
In alto, sopra ogni dichiarazione, scriviamo lo spazio dei nomi per gestire alcuni aspetti del codice per fare uso delle classi per realizzare il nostro esempio.
Qui di seguito si riporta la dichiarazione dei spazio dei nomi per entrambi i linguaggi.

VB.Net
Imports System.Net.Mail
Imports System.IO
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
using System.Windows.Forms;
using System.IO;
using System.Net.Mail;

A questo punto dobbiamo creare a livello di classe, due oggetti per la creazione della barra e del pulsante che al click verrà eseguito la conversione del file

Qui di seguito le dichiarazioni per entrambi i linguaggi.

VB.Net
Dim ComBar As Office.CommandBar
Dim pulsante As Office.CommandBarButton
C#
Microsoft.Office.Core.CommandBar ComBar;
Microsoft.Office.Core.CommandBarButton pulsante;

Si continua a scrivere le istruzioni per la creazione della barra e del pulsante, e la gestione dell’evento click del pulsante.
Qui di seguito tali dichiarazione.

VB.Net
Private Sub CreaBarra()
ComBar = Globals.ThisAddIn.Application.ActiveExplorer().CommandBars.Add("Esempio EML", Office.MsoBarPosition.msoBarTop, False, True)
ComBar.Protection = Office.MsoBarProtection.msoBarNoCustomize
ComBar.Visible = True
End Sub
Private Sub CreaPulsante()
'aggiungo il pulsante alla barra ed imposto la proprietà testo oltre al gestore di evento click
pulsante = TryCast(ComBar.Controls.Add(Office.MsoControlType.msoControlButton, Type.Missing, Type.Missing, Type.Missing, True), Office.CommandBarButton)
pulsante.Caption = "Salva Formato EML VB"
pulsante.Style = Office.MsoButtonStyle.msoButtonIconAndCaption
pulsante.TooltipText = "Salva l'email in formato eml."
pulsante.FaceId = 2605
AddHandler pulsante.Click, AddressOf pulsante_Click
End Sub
C#
private void CreaBarra()
{
ComBar = Globals.ThisAddIn.Application.ActiveExplorer().CommandBars.Add(
"Esempio EML",
Office.MsoBarPosition.msoBarTop,
false,
true);
ComBar.Protection = Office.MsoBarProtection.msoBarNoCustomize;
ComBar.Visible = true;
}
//funzione per la creazione del pulsante
private void CreaPulsante()
{
//aggiungo il pulsante alla barra ed imposto la proprietà testo oltre al gestore di evento click
pulsante = ComBar.Controls.Add(Office.MsoControlType.msoControlButton, Type.Missing, Type.Missing, Type.Missing, true) as Office.CommandBarButton;
pulsante.Caption = "Salva Formato EML";
pulsante.Style = Office.MsoButtonStyle.msoButtonIconAndCaption;
pulsante.TooltipText = "Salva l'email in formato eml.";
pulsante.FaceId = 2605;
//gestore dell'evento click
pulsante.Click += new Office._CommandBarButtonEvents_ClickEventHandler(pulsante_Click);
}

Queste funzioni saranno richiamate nell’evento “StartUp del compoenente.
Qui di seguito il codice.

VB.Net
Private Sub ThisAddIn_Startup() Handles Me.Startup
CreaBarra()
CreaPulsante()
End Sub
C#
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
CreaBarra();
CreaPulsante();
}

Nell’evento click del pulsante, scriveremo il codice che permette di gestire l’email, in particolare la possibilità di verificare se l’email selezionata è di tipo pec, in tal caso verranno eseguite le funzioni per l’esportazione.
Qui di seguito si riporta il codice per i linguaggi VB.Net e C#

VB.Net
Private Sub pulsante_Click(Ctrl As Office.CommandBarButton, ByRef CancelDefault As Boolean)
Try
'Verifico che ho selezionato almeno una email
If Me.Application.ActiveExplorer().Selection.Count > 0 Then
Dim PR_ATTACH_DATA_BIN As String = "http://schemas.microsoft.com/mapi/proptag/0x37010102"
Dim objectSelezionato As [Object] = Me.Application.ActiveExplorer().Selection(1)
If TypeOf objectSelezionato Is Outlook.MailItem Then
Dim mailItemSelezionato As Outlook.MailItem = TryCast(objectSelezionato, Outlook.MailItem)
For Each elemento As Outlook.Attachment In mailItemSelezionato.Attachments
If elemento.FileName.Contains(".eml") Or elemento.FileName.Contains("daticert.xml") Then
Esporta(mailItemSelezionato)
End If
Next
End If
End If
Catch ex As Exception
System.Windows.Forms.MessageBox.Show("Errore: " + ex.Message)
End Try
End Sub
C#
void pulsante_Click(Office.CommandBarButton Ctrl, ref bool CancelDefault)
{
try
{
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.WaitCursor;
//Verifico che ho selezionato almeno una email
if (this.Application.ActiveExplorer().Selection.Count > 0)
{
Object selObject = Application.ActiveExplorer().Selection[1];
if (selObject is Outlook.MailItem)
{
Outlook.MailItem mailItemSelezionato =
(selObject as Outlook.MailItem);
foreach (Outlook.Attachment elemento in mailItemSelezionato.Attachments)
{
if (elemento.FileName.Contains(".eml") || elemento.FileName.Contains("daticert.xml"))
{
Esporta(mailItemSelezionato);
}
}
}
else
{
System.Windows.Forms.MessageBox.Show("Selezionare una email", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
catch (Exception ex)
{
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Default;
System.Windows.Forms.MessageBox.Show("Si è verificato il seguente errore: " + ex.Message);
}
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Default;
}


Si riporta il codice per la gestione dell’esportazione nel quale verrà creato un oggetto di tipo mailMessage, con il quale si generà il file di tipo eml con le informazioni e dati presenti nell’oggetto di tipo mailItem.
La funzione avrà il compito di trasformare i due oggetti e cancellare i file temporanei.
Qui di seguito le dichiarazioni per entrambi i linguaggi.

VB.Net
Private Sub Esporta(ByVal mailItemSelezionato As Outlook.MailItem)
Try
Dim application As Outlook.Application = New Outlook.Application()
For Each elemento As Outlook.Attachment In mailItemSelezionato.Attachments
If elemento.FileName.Contains(".eml") Then
Dim percorsoTemporaneo As String = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\TempFile\"
If Directory.Exists(percorsoTemporaneo) = False Then
Directory.CreateDirectory(percorsoTemporaneo)
End If
elemento.SaveAsFile(percorsoTemporaneo & "\" + elemento.FileName)
Dim mailItemEsistente As Outlook.MailItem = application.CreateItemFromTemplate(percorsoTemporaneo & "\" + elemento.FileName)
Dim mailMessaggeNuovo As New MailMessage()
mailMessaggeNuovo.From = New System.Net.Mail.MailAddress(mailItemEsistente.SenderEmailAddress)
mailMessaggeNuovo.[To].Add(mailItemEsistente.[To])
mailMessaggeNuovo.Body = mailItemEsistente.Body
If Not String.IsNullOrEmpty(mailItemEsistente.CC) Then mailMessaggeNuovo.CC.Add(mailItemEsistente.CC)
If Not String.IsNullOrEmpty(mailItemEsistente.BCC) Then mailMessaggeNuovo.Bcc.Add(mailItemEsistente.BCC)
mailMessaggeNuovo.Subject = mailItemEsistente.Subject
If mailItemEsistente.Attachments.Count > 0 Then
For Each allegatoPec As Outlook.Attachment In mailItemEsistente.Attachments
allegatoPec.SaveAsFile(percorsoTemporaneo & "\" + allegatoPec.FileName)
mailMessaggeNuovo.Attachments.Add(New System.Net.Mail.Attachment(percorsoTemporaneo & "\" + allegatoPec.FileName))
Next
End If
Dim emailConvertita As String = ConvertiEmailInEML(mailMessaggeNuovo)
File.Delete(emailConvertita)
Directory.Delete(Path.GetDirectoryName(emailConvertita))
File.Delete(percorsoTemporaneo & "\" + elemento.FileName)
End If
Next
Catch ex As Exception
System.Windows.Forms.MessageBox.Show("Si è verificato il seguente errore: " & ex.Message)
End Try
End Sub
C#
private void Esporta(Outlook.MailItem mailItemSelezionato)
{
try
{
Outlook.Application application = new Outlook.Application();
const string PR_ATTACH_DATA_BIN = "http://schemas.microsoft.com/mapi/proptag/0x37010102";
foreach (Outlook.Attachment elemento in mailItemSelezionato.Attachments)
{
if (elemento.FileName.Contains(".eml"))
{
string percorsoTemporaneo = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
elemento.SaveAsFile(percorsoTemporaneo + "\\" + elemento.FileName);
Outlook.MailItem mailItemEsistente = application.CreateItemFromTemplate(percorsoTemporaneo + "\\" + elemento.FileName);
MailMessage mailMessaggeNuovo = new  MailMessage();
mailMessaggeNuovo.From = new System.Net.Mail.MailAddress(mailItemEsistente.SenderEmailAddress);
mailMessaggeNuovo.To.Add(mailItemEsistente.To);
mailMessaggeNuovo.Body = mailItemEsistente.Body;
if (!string.IsNullOrEmpty(mailItemEsistente.CC))
mailMessaggeNuovo.CC.Add(mailItemEsistente.CC);
if (!string.IsNullOrEmpty(mailItemEsistente.BCC))
mailMessaggeNuovo.Bcc.Add(mailItemEsistente.BCC);
mailMessaggeNuovo.Subject = mailItemEsistente.Subject;
//Allegato
if (mailItemEsistente.Attachments.Count > 0)
{
foreach (Outlook.Attachment allegatoPec in mailItemEsistente.Attachments)
{
mailMessaggeNuovo.Attachments.Add(new System.Net.Mail.Attachment(new MemoryStream(allegatoPec.PropertyAccessor.GetProperty(PR_ATTACH_DATA_BIN)), allegatoPec.FileName));
}
}
string emailConvertita = ConvertiEmailInEML(mailMessaggeNuovo);
File.Delete(emailConvertita);
Directory.Delete(Path.GetDirectoryName(emailConvertita));
File.Delete(percorsoTemporaneo + "\\" + elemento.FileName);
}
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("Si è verificato il seguente errore: " + ex.Message);
}
}

Siamo giunti all’ultima parte della stesura del codice.
La funzione ConvertiEmailinEml permetterà di trasformare in un file sul computer l’email nel formato “eml” tramite la classe smtclient, che impostando la proprietà “PickupDirectoryLocation” genera un file.
Si riporta il frammento di codice per entrambi i linguaggi.

VB.Net
Private Function ConvertiEmailInEML(ByVal mailMessaggeNuovo As MailMessage) As String
Try
mailMessaggeNuovo.SubjectEncoding = System.Text.Encoding.UTF8
mailMessaggeNuovo.BodyEncoding = System.Text.Encoding.UTF8
mailMessaggeNuovo.Headers.Add("X-VirusFound", "false")
mailMessaggeNuovo.Headers.Add("X-Spam", "Score=1.5")
Using clientSMTP = New SmtpClient()
Dim id = Guid.NewGuid()
Dim CartellaTemporanea = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
CartellaTemporanea = Path.Combine(CartellaTemporanea, "TempEmail")
CartellaTemporanea = Path.Combine(CartellaTemporanea, id.ToString())
If Not Directory.Exists(CartellaTemporanea) Then
Directory.CreateDirectory(CartellaTemporanea)
End If
clientSMTP.UseDefaultCredentials = True
clientSMTP.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.SpecifiedPickupDirectory
clientSMTP.PickupDirectoryLocation = CartellaTemporanea
clientSMTP.Send(mailMessaggeNuovo)
Dim percorsoFileEML = Directory.GetFiles(CartellaTemporanea).Single()
Return percorsoFileEML
End Using
Catch ex As Exception
System.Windows.Forms.MessageBox.Show("Si è verificato il seguente errore: " & ex.Message)
Return ""
End Try
End Function
C#
private string ConvertiEmailInEML(MailMessage mailMessaggeNuovo)
{
try
{
mailMessaggeNuovo.SubjectEncoding = System.Text.Encoding.UTF8;
mailMessaggeNuovo.BodyEncoding = System.Text.Encoding.UTF8;
//intestazione da aggiungerne altre se si vuole
mailMessaggeNuovo.Headers.Add("X-VirusFound", "false");
mailMessaggeNuovo.Headers.Add("X-Spam", "Score=1.5");
using (var clientSMTP = new  SmtpClient())
{
var id = Guid.NewGuid();
var CartellaTemporanea = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
CartellaTemporanea = Path.Combine(CartellaTemporanea, "TempEmail");
CartellaTemporanea = Path.Combine(CartellaTemporanea, id.ToString());
if (!Directory.Exists(CartellaTemporanea))
{
Directory.CreateDirectory(CartellaTemporanea);
}
clientSMTP.UseDefaultCredentials = true;
clientSMTP.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.SpecifiedPickupDirectory;
//indico che viene generato il file anzichè spedito
clientSMTP.PickupDirectoryLocation = CartellaTemporanea;
clientSMTP.Send(mailMessaggeNuovo);
var percorsoFileEML = Directory.GetFiles(CartellaTemporanea).Single();
return percorsoFileEML;
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("Si è verificato il seguente errore: " + ex.Message);
return "";
}
}

Conclusioni


L’articolo ha voluto fornire interessanti spunti sulla programmazione Office, in particolare con Outlook tramite la tecnologia VSTO, realizzando un componente aggiuntivo che permette di convertire una email di Outlook in un file di tipo “eml” ma solo se tale email è di tipo “PEC”.
Le potenzialità offerte da questa tecnologia, rendono facile lo sviluppo di Office ed al tempo stesso di estendere le funzionalità del pacchetto office, in questo caso di Microsoft Office Outlook, con interessanti aspetti che il programmatore vuole aggiungere.