Inviare e-mail con Visual Basic 2005 e .NET 2.0

Premessa
Come molti sanno, il .NET Framework 2.0 facilita la realizzazione di molte procedure grazie ai numerosi Namespace e alle tonnellate di classi che coprono verosimilmente la maggior parte degli aspetti della programmazione. Tra i molti Namespace, alcuni riguardano l’interazione con Internet e con le reti in generale. Proprio a questo riguardo il Framework 2.0 espone il Namespace System.Net che, come il nome suggerisce, implementa funzionalità per la programmazione in rete. Tale Namespace incapsulaSystem.Net.Mail, un ulteriore Namespace specifico per l’invio di messaggi di posta elettronica tramite alcune righe di codice.

Questo articolo si propone di introdurre il Namespace System.Net.Mail, all’interno di un’applicazione Windows Forms di esempio scritta in Visual Basic 2005. Si vedrà come creare ed inviare messaggi di posta elettronica completi di allegati e si faranno alcune considerazioni più approfondite su alcune caratteristiche del Namespace, sebbene non applicate al codice a corredo. Per ulteriori dettagliate informazioni sul Namespace System.Net.Mail, si rimanda alla documentazione MSDN all’indirizzo: http://msdn2.microsoft.com/it-it/library/system.net.mail(vs.80).aspx.

In teoria, è possibile inviare una semplice e-mail con sole tre righe di codice, come mostrato in un mio post. Come però si vedrà tra breve, grazie alle classi di questoNamespace è possibile avere un controllo completo sui messaggi di posta, al fine di renderli più ricchi e complessi.

Per proseguire nella lettura dell’articolo consiglio di scaricare l’applicazione di esempio, disponibile nell’area download di VB T&T.

La logica
Seguendo la logica secondo la quale tutto in .NET è un oggetto, un messaggio di posta elettronica è rappresentato una classe, composta da un insieme di elementi, come ad esempio il destinatario, l’oggetto, il corpo del messaggio e così via. Tale classe è System.Net.Mail.MailMessage. Il primo passaggio, pertanto, è quello di istanziare un nuovo oggetto MailMessage e “riempirlo” con tutti i dati necessari all’invio del messaggio.

Avere a disposizione il nuovo oggetto non è però sufficiente, dal momento che, una volta preparato il messaggio, è necessario concretizzare il suo invio tramite l’accesso a un servizio di posta elettronica; questo si ottiene grazie alle credenziali (ad esempio nome utente e password) e ad alcune configurazioni (come ad esempio l’indirizzo del server Smtp). Il .NET Framework 2.0 fornisce System.Net.Mail.SmtpClient, classe che consente di impostare alcuni parametri di configurazione e di inviare il messaggio di posta creato precedentemente grazie all’istanza della classe MailMessage.

Si vedrà ora il codice dell’applicazione di esempio, costituita da un unico form. Il codice è commentato al suo interno, per renderne più fluida la lettura. Dopo il codice, verranno fatte alcune considerazioni per meglio spiegarne l’utilizzo.

Un’applicazione Windows Forms di esempio: EMailer
L’applicazione di esempio, come detto, è costituita da un unico form e da alcuni controlli. Se non si desidera utilizzare il progetto sorgente scaricato, si apra Visual Studio 2005 (o Visual Basic Express) e si crei un nuovo progetto Windows Forms di Visual Basic. Il form deve apparire come riportato nella seguente figura:

Come si può facilmente intuire, è necessario specificare l’indirizzo di posta del destinatario e il suo nome (composto, tipicamente, da nome e cognome). Quest’ultima caratteristica non è obbligatoria ma viene utilizzata per motivi didattici, come si vedrà più avanti. E’ poi necessario specificare l’indirizzo e-mail di chi legge per conoscenza, l’oggetto del messaggio e il corpo del messaggio stesso. Tramite il pulsante “Sfoglia”, è possibile anche selezionare uno o più file da allegare al messaggio. Si noti che, al fine di rendere più semplice il codice, non ho volutamente implementato il controllo della validità del contenuto delle caselle di testo, cosa che invece andrebbe fatta (ad esempio per verificare che le caselle di testo non siano vuote). Pertanto, al fine di eseguire correttamente l’applicazione di esempio, è necessario inserire dei valori validi in ciascuna casella di testo. Di seguito riporto il codice del form, opportunamente commentato al suo interno:

  'Consente di abbreviare le successive chiamate alle classi del namespace
  Imports System.Net.Mail

  Public Class Form1

    'Dichiara un oggetto "contenitore" per il messaggio di posta
    Dim mex As MailMessage

    'Dichiara un oggetto destinato a contenere l'indirizzo di posta del destinatario
    Dim destAddress As MailAddress

    'Dichiara un oggetto destinato a contenere l'indirizzo di posta di chi legge per conoscenza
    Dim ccAddress As MailAddress

    'Dichiara un oggetto che conterrà un singolo allegato
    Dim attachment As Attachment

    'Istanzia l'autore del messaggio di posta
    Dim author As New MailAddress("miouser@mioprovider.it", "Nome Cognome")

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                                                                          Handles SendMessage.Click

      'Istanzia un nuovo indirizzo di posta, dato l'indirizzo e.mail e il nome completo dell'autore
      destAddress = New MailAddress(DestinationAddress.Text, DestinationName.Text)

      'Istanzia un nuovo oggetto relativo alla copia per conoscenza,dato l'indirizzo e.mail
      ccAddress = New MailAddress(CC.Text)

      'Istanzia un nuovo oggetto MailMessage, che contiene tutti gli elementi necessari per
      'inviare il messaggio di posta
      mex = New MailMessage

      With mex

        'Assegna agli elementi del messaggio ciò che è stato specificato nel form
        'oltre all'autore del messaggio, istanziato precedentemente
        .Subject = Subject.Text
        .Sender = author
        .Body = Body.Text
        .From = author
        .ReplyTo = author
        .To.Add(destAddress)
        .CC.Add(ccAddress)

        'Specifica quale messaggio di notifica deve essere inviato al mittente
        'In questo caso solo se l'invio del messaggio fallisce.
        .DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure
      End With

      'Esegue un ciclo sulla Listbox al fine di aggiungere alla Collection
      'che contiene gli allegati (Attachments) ogni file elencato.
      If ListBox1.Items.Count > 0 Then
        For Each Item As String In ListBox1.Items
          Attachment = New Attachment(Item)

          Mex.Attachments.Add(Attachment)

          Attachment = Nothing
        Next
      End If

      Dim Client As New SmtpClient("smtp.mioprovider.it")

      Try
        'abilita l'utilizzo della crittografia nell'invio dei messaggi
        'si tenga conto che non tutti i destinatari possono supportare questo metodo.
        'Client.EnableSsl = True

        'E' possibile specificare l'indirizzo IP dell'Host:
        'Client.Host = "210.333.3.1"

        Client.Credentials = New System.Net.NetworkCredential("miouserID", "password")
        Client.Send(Mex)

      Catch ex As InvalidOperationException
        MessageBox.Show("Non è stato specificato il nome Host del server")
      Catch ex As SmtpFailedRecipientException
        MessageBox.Show("Tentativo di invio al server locale, ma non è presente una mailbox")
      Catch ex As SmtpException
        MessageBox.Show("Utente non valido/Host non trovato/Altro errore in fase di invio")
      Catch ex As Exception
        MessageBox.Show(ex.ToString)
      End Try
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                                                                               Handles Button2.Click
      With OFD1
        .Filter = "Tutti i files|*.*"
        If .ShowDialog = Windows.Forms.DialogResult.OK Then
          ListBox1.Items.Add(.FileName)
        End If
      End With
    End Sub

    Private Sub CloseButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                                                                           Handles CloseButton.Click
      Application.Exit()
    End Sub
  End Class

Considerazioni di dettaglio sul codice
Per meglio focalizzare l’attenzione sulle caratteristiche del codice sopra descritto,vengono di seguito schematizzati i punti principali da analizzare:

  •  La direttiva Imports iniziale serve per abbreviare le chiamate agli oggetti che appartengono al Namespace System.Net.Mail;
  •  Si dichiara un oggetto mex di tipo MailMessage, che verrà successivamente istanziato e che costituirà il messaggio di posta vero e proprio;
  •  Si dichiarano due oggetti di tipo MailAddress (destAddress e ccAddress) che si riferiscono rispettivamente all’indirizzo di posta del destinatario del messaggio e all’indirizzo di posta della persona che leggerà il messaggio per conoscenza;
  •  Si dichiara un oggetto di tipo Attachment al quale, una volta istanziato, sarà possibile assegnare il nome di un file da allegare al messaggio di posta. Ogni oggetto di tipoMailMessage espone un membro chiamato Attachments che è una Collection di elementi di tipo Attachment.
  •  Si istanzia un oggetto author di tipo MailAddress. La classe MailAddress permette di specificare un indirizzo di posta elettronica (sia esso del mittente che del destinatario). Il costruttore di questa classe prevede più overload. Quello utilizzato nell’esempio permette di specificare sia l’indirizzo di posta del mittente che il suo nome completo.
  •  Quando si fa clic sul pulsante “Invia”, dapprima viene istanziato un oggetto destAddress, ancora di tipo MailAddress, che contiene l’indirizzo di posta e il nome del destinatario. Come si può vedere nel punto successivo (nuova istanza dell’oggetto ccAddress) questo non è obbligatorio, infatti è possibile istanziare il nuovo oggetto specificando semplicemente l’indirizzo di posta.

La parte più interessante del codice è relativa all’utilizzo dell’oggetto mex di tipo MailMessage. Ogni campo del form contiene un valore che andrà ad impostare delle proprietà dell’oggetto, come rappresentato nella seguente tabella:

Membro Significato
Subject Specifica l’oggetto del messaggio
Sender Specifica l’autore del messaggio (oggetto di tipo MailAddress)
Body Contiene il corpo del messaggio di posta
From Indica l’indirizzo di partenza del messaggio
ReplyTo Specifica l’indirizzo a cui deve essere diretta la risposta
DeliveryNotificationsOptions Permette di specificare il tipo di messaggio che deve essere inviato al mittente a seconda di cosa succede in fase di invio del messaggio (in questo caso se l’invio fallisce).

I membri To e CC degli oggetti di tipo MailMessage contengono uno o più indirizzi di posta elettronica, rispettivamente dei destinatari e delle persone che leggono per conoscenza.To e CC sono in realtà delle collection di oggetti di tipo MailAddress; grazie al metodo Add di tali collection è possibile aggiungere un indirizzo al gruppo di indirizzi.

Il concetto di collection ritorna anche con riferimento agli allegati. Come detto in precedenza, ogni allegato è in realtà un oggetto di tipo Attachment. Gli oggetti di tipoMailMessage, come l’oggetto mex utilizzato nell’esempio, implementano un membro chiamato Attachments, che è una collection di allegati (ossia di oggetti Attachment). Ciò posto, il codice successivo verifica che la ListBox non sia vuota. Dopodiché, esegue un ciclo For..Each durante il quale viene istanziato un nuovo oggetto Attachment per ogni file contenuto nella ListBox; tale nuovo oggetto viene poi aggiunto alla collection di allegati tramite il metodo Add.

Si passa poi ad esaminare il codice relativo all’invio vero e proprio del messaggio:

  •  Si istanzia un nuovo oggetto Client di tipo SmtpClient. E’ qui che va specificato l’indirizzo del server Smtp del proprio provider di posta elettronica, al quale il .NET Framework si connetterà per l’invio del messaggio.
  •  Nel codice è presente una riga non operativa (a causa del commento che la precede), che mostra come attivare l’utilizzo della crittografia tramite certificati SSL (Client.EnableSLL = True). Tale riga di codice è stata resa inattiva perché non tutti i destinatari supportano la ricezione di messaggi crittografati, ma volevo comunque illustrare come sia possibile utilizzare tale tecnica per rendere più sicuri i propri messaggi.
  •  Prima di inviare il messaggio, è necessario fornire le proprie credenziali di accesso al servizio di posta, come ad esempio il nome utente e la password, mediante l’impostazione del valore della proprietà Credentials dell’oggetto Client. Tale proprietà deve ricevere l’istanza di un oggetto di tipo System.Net.NetworkCredential. Quest’ultimo oggetto permette, per l’appunto, di specificare le credenziali necessarie.
  •  Il metodo Send consente di inviare il messaggio di posta, che corrisponde all’oggetto MailMessage precedentemente istanziato. Infine, alcune considerazioni sulle eccezioni intercettate in questo frangente:
  •  L’eccezione InvalidOperationException indica che non è stato specificato il nome del server per l’accesso al servizio;
  •  L’eccezione SmtpFailedRecipientException indica che si è tentato di inviare un messaggio tramite il server locale, ma questo non dispone di un contenitore di mailbox;
  •  L’eccezione SmtpException, più generica, indica tutti gli altri errori di invio, quali, ad esempio, l’autenticazione fallita dell’utente o il fatto che il server specificato non è stato trovato.

In sintesi, quando l’utente clicca sul pulsante “Invia”, il codice assegna all’istanza dell’oggetto MailMessage tutte le informazioni di cui necessita, compresi gli allegati e tenta di inviare il messaggio tramite un oggetto di tipo SmtpClient.

Ulteriori funzionalità delle classi utilizzate
Le classi finora utilizzate espongono ulteriori funzionalità. L’elenco seguente ne elenca solo alcune, ma è possibile consultare la documentazione MSDN on-line o a corredo di Visual Studio per i dettagli:

  •  Impostando su True la proprietà IsBodyHtml dell’oggetto MailMessage, è possibile inviare e-mail in formato Html. Questo presuppone che il corpo del messaggio, contenuto nel membro Body contenga degli idonei tag Html;
  •  Per inglobare immagini nei messaggi in formato Html, è possibile utilizzare congiuntamente le classi AlternateView e LinkedResource;
  •  Si può modificare la priorità del messaggio utilizzando la proprietà Priority degli oggetti MailMessage;
  •  E’ possibile impostare l’indirizzo IP dell’Host utilizzando la proprietà Host della classe SmtpClient;
  •  Si possono inviare e-mail in modalità asincrona, implementando un gestore per l’evento SendCompleted esposto dagli oggetti SmtpClient ed utilizzando il metodoSendAsync dei medesimi oggetti.

Problemi noti
E’ possibile che, utilizzando il codice sopra evidenziato, si riscontrino errori nell’invio dei messaggi di posta. Il problema dipende prevalentemente dalle configurazioni passate all’oggetto SmtpClient (ma potrebbe anche dipendere dall’utilizzo di software anti-virus o firewall che blocchino l’utilizzo di talune porte). Nel caso abbiate difficoltà, vi consiglio di leggere questo thread presente nell’archivio di VB T&T.

Both comments and pings are currently closed.

Comments are closed.