ASP.Net Enviar correo electrónico con ficheros adjuntos

Otra de las preguntas bastante frecuente por los foros de Microsoft es la posibilidad de enviar un correo electrónico desde una página pero que contenga uno o varios ficheros adjuntos. Aunque en una búsqueda genérica nos aparecen miles de entradas sobre el tema, intentaremos, en esta ocasión, crear un ejemplo lo más sencillo posible.

El envío de un correo electrónico es relativamente sencillo, sobre todo, si nos abstraemos de la configuración del correo y dejamos los datos en el archivo web.config.

   1: <system.net>
   2:   <mailSettings>
   3:     <smtp from="cuentaValidaDelServidor">
   4:       <network host="servidorSMTP"
   5:                userName ="usuarioServidorSMTP"
   6:                password="contraseñaServidorSMTP"
   7:                />
   8:     </smtp>
   9:   </mailSettings>
  10: </system.net>

De esta manera, el envío de correo sería algo así como:

   1: void enviaCorreo()
   2: {
   3:     using (System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage())
   4:     {
   5:         // Dirección de destino
   6:         message.To.Add("cuentaDestino");
   7:         // Asunto 
   8:         message.Subject = "Asunto del mensaje";
   9:         // Mensaje 
  10:         message.Body = "Cuerpo del mensaje";
  11:  
  12:         // Se envía el mensaje
  13:         System.Net.Mail.SmtpClient smpt = new System.Net.Mail.SmtpClient();
  14:         smpt.Send(message);
  15:     }
  16: }

Ahora que ya tenemos definido el envío del correo, nos podemos centrar en cómo hacerlo desde una página ASP.Net.

Para el envío de un mensaje estándar (sin datos adjuntos) bastaría con definir unos cuadros de texto para el destinatario, el asunto y el mensaje, pero a la hora de enviar ficheros adjuntos podemos encontrarnos con que otro problema, pues deberemos tener en cuenta lo siguiente:

  • Si vamos a enviar ficheros adjuntos, éstos deberán encontrarse en el servidor, nunca el cliente
  • Salvo que usemos controles externos, el control UploadFile sólo nos permite subir un fichero a la vez
  • queremos que el número de ficheros a enviar sea variable.

Con estas premisas, sólo nos queda hacer una cosa:

  1. Deberemos subir los ficheros, de uno en uno y previo al envío del correo.
  2. El usuario se puede equivocar a la hora de subir un fichero y debería poder borrarlo

Esto nos lleva a pensar que, además de tener los ficheros en una carpeta del servidor, deberemos añadir los nombres de dichos ficheros en algún control, de tal manera que el usuario pueda modificarlo. Para el ejemplo actual escojo uno sencillo, el ListBox, que nos permitirá mostrar al cliente los ficheros subidos y, en caso necesario, podrá eliminar alguna entrada. A nivel de diseño, creo una tabla con los controles UploadFile y el ListBox que encapsulo dentro de un UpdatePanel.

   1: <asp:UpdatePanel ID="pnUpdateFile" runat="server" UpdateMode="Conditional">
   2:     <Triggers>
   3:         <asp:PostBackTrigger ControlID="cmdAddFile" />
   4:     </Triggers>
   5:     <ContentTemplate>
   6:         <table>
   7:             <tr>
   8:                 <td style="width: 450px;">
   9:                     <asp:FileUpload ID="fUpload" runat="server" /></td>
  10:                 <td style="width: 50px;">
  11:                     <asp:Button ID="cmdAddFile" 
  12:                         runat="server" 
  13:                         Text="+" 
  14:                         ToolTip="Añade el fichero a la lista"
  15:                         OnClick="cmdAddFile_Click" />
  16:                 </td>
  17:             </tr>
  18:             <tr>
  19:                 <td>
  20:                     <asp:ListBox ID="lstFiles" runat="server"></asp:ListBox>
  21:                 </td>
  22:                 <td>
  23:                     <asp:Button ID="cmdDelFile" 
  24:                         runat="server" 
  25:                         Text="-" 
  26:                         ToolTip="Elimina el fichero seleccionado de la lista"
  27:                         OnClick="cmdDelFile_Click" />
  28:                 </td>
  29:             </tr>
  30:         </table>
  31:     </ContentTemplate>
  32: </asp:UpdatePanel>

Bueno, ahora que ya tenemos definida la estructura HTML procederemos a implementar el code-behind delos botones que nos permitirán subir ficheros al servidor (+) y eliminarlos (-)

   1: private string tempPath = @"~/uploads/temp";
   2:  
   3:    protected void cmdAddFile_Click(object sender, EventArgs e)
   4:    {
   5:  
   6:        FileUpload f = fUpload;
   7:  
   8:        // No se hace nada si no hay fichero
   9:        if (!f.HasFile)
  10:            return;
  11:  
  12:        // Se crea un Item para el ListBox
  13:        //  - Value: Nombre del fichero
  14:        //  - Text : Texto para mostrar
  15:        ListItem item = new ListItem();
  16:        item.Value = f.FileName;
  17:        item.Text = f.FileName + 
  18:                    " (" + f.FileContent.Length.ToString("N0") + 
  19:                    " bytes).";
  20:  
  21:        // Se sube el fichero a la carpeta temporal
  22:        f.SaveAs(Server.MapPath(Path.Combine(tempPath, item.Value)));
  23:  
  24:        // Se deja el nombre del fichero en el ListBox
  25:        lstFiles.Items.Add(item);
  26:    }
  27:  
  28:    protected void cmdDelFile_Click(object sender, EventArgs e)
  29:    {
  30:        ListBox lb = lstFiles;
  31:        // Se comprueba que exista algún item seleccionado
  32:        if (lb.SelectedItem == null)
  33:            return;
  34:  
  35:        // Se elimina el fichero seleccionado
  36:        borraEntrada(lb.SelectedItem.Value);
  37:    }
  38:  
  39:    /// <summary>
  40:    /// Elimina el fichero de la carpeta temporal y del ListBox.
  41:    /// </summary>
  42:    /// <param name="fileName"></param>
  43:    private void borraEntrada(string fileName)
  44:    {
  45:        string fichero = Server.MapPath(Path.Combine(tempPath, fileName));
  46:        File.Delete(fichero);
  47:  
  48:        ListItem l = lstFiles.Items.FindByValue(fileName);
  49:        if (l != null)
  50:            lstFiles.Items.Remove(l);
  51:    }

 

Una vez hemos cumplido los requisitos iniciales, ya tan sólo nos queda crear el botón para que envíe el mensaje, leyendo los archivos de los Items del ListBox.

   1: /// <summary>
   2:   /// Envía el correo electrónico.
   3:   /// Los datos de configuración del servidor de correo SMTP se configuran 
   4:   /// en el fichero web.config.
   5:   /// </summary>
   6:   private void enviaCorreo()
   7:   {
   8:       using (System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage())
   9:       {
  10:           // Dirección de destino
  11:           message.To.Add(txtPara.Text);
  12:           // Asunto 
  13:           message.Subject = txtAsunto.Text;
  14:           // Mensaje 
  15:           message.Body = txtMensaje.Text;
  16:  
  17:           // Se recuperan los ficheros
  18:           foreach (ListItem l in lstFiles.Items)
  19:           {
  20:               // Lectura del nombre del fichero
  21:               string fichero = Server.MapPath(Path.Combine(tempPath, l.Value));
  22:  
  23:               // Adjuntado del fichero a la colección Attachments
  24:               message.Attachments.Add(new System.Net.Mail.Attachment(fichero));
  25:           }
  26:  
  27:           // Se envía el mensaje y se informa al usuario
  28:           System.Net.Mail.SmtpClient smpt = new System.Net.Mail.SmtpClient();
  29:           string mensaje = string.Empty;
  30:           try
  31:           {
  32:               smpt.Send(message);
  33:               mensaje = "Correo enviado con éxito";
  34:           }
  35:           catch (Exception ex)
  36:           {
  37:               mensaje = "Ocurrió un error: " + ex.Message;
  38:           }
  39:           resultado.Text = mensaje;
  40:       }
  41:  
  42:       // Se borran los ficheros de la carpeta temporal
  43:       while (lstFiles.Items.Count > 0)
  44:       {
  45:           borraEntrada(lstFiles.Items[0].Value);
  46:       }
  47:   }

Como va siendo habitual, por si me he dejado algo en el Copy & Paste o por si alguien quiere descargar el ejemplo, dejo un enlace con la aplicación. Como se puede apreciar, he intentado hacer uso de Themes y hoja de estilos externas para dejar en la página de envío tan sólo aquellos elementos que se refieran al envío del correo.

Enlace

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *