lunes, 1 de marzo de 2010

Enviar pagina ASP.NET por email

news Me consultaron cómo hacer para enviar una página web por email.
Según lo que se me ocurre, pueden darse tres casos:
1.- Recuperas todo el contenido HTML de una página externa,
Esta es la forma más rápida y fácil, pero no la más óptima… ya que depende de internet, pues cada imagen u hoja de estilo css lo jala desde internet, osea, si te desconectas de internet.. verás un texto mal formateado y sin imágenes y además todo descuadrado.
Cómo lo haría? Aquí hay un post al respecto.
2.- Recuperas parte (o todo) el contenido de la actual página aspx,
Dado que tal vez algunos controles (por ejemplo botones, etc) no quieras incluir en el correo.
Cómo lo haría? Una forma conveniente es incluir dentro de un asp:panel todo lo que quiero enviar por correo, y lo que no quiero enviar puede ir en otro panel.
Ejemplo:
<asp:Panel ID="pnlSendByEmail" runat="server">
<div style="text-align: center; background-color: #b4d9b0">
<h1>Newsletter semanal</h1>
<p>
<asp:Label ID="lblRespuesta" runat="server" Text="Esto es el contenido del newsletter"></asp:Label>
</p>
<asp:Image ID="Image1" ImageUrl="http://www.mmoran.com.ar/images/plag-rata1.gif" runat="server" />
<p>
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="http://www.google.com" Text="Enlace a Google"></asp:HyperLink>
</p>
<asp:Image ID="Image2" ImageUrl="http://blog.pucp.edu.pe/media/134/20070502-cachorrito.jpg" runat="server" />
</div>
</asp:Panel>

<asp:Panel ID="pnlNotSendByEmail" runat="server">
<asp:Button ID="btnSend" runat="server" Text="Enviar esta página por email" />
</asp:Panel>

Luego, en el botón Enviar, concateno las cabeceras de página con el contenido que extraigo del asp:panel… y se forma la página web completa:

Protected Sub btnSend_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSend.Click

Dim EmailBody As String = GetHTML()
SendEmail(EmailBody)

End Sub

Public Overloads Overrides Sub VerifyRenderingInServerForm(ByVal control As Control)

End Sub

Private Function GetHTML()

Dim stringWrite As System.IO.StringWriter = New System.IO.StringWriter()
Dim htmlWrite As System.Web.UI.HtmlTextWriter = New HtmlTextWriter(stringWrite)
pnlSendByEmail.RenderControl(htmlWrite)

Dim sb As New System.Text.StringBuilder
sb.Append("<html>")
sb.Append("<head>")
sb.Append("<style type='text/css'>")
sb.Append("* { font-family: Trebuchet MS;}")
sb.Append("</style>")
sb.Append("</head>")
sb.Append("<body>")

sb.Append(stringWrite.ToString)

sb.Append("</body>")
sb.Append("</html>")

Return sb.ToString

End Function

Private Sub SendEmail(ByVal EmailBody As String)

'desde aquí puedes enviar tu email...

End Sub

Hay que resaltar que:

2.1.- dado que sólo enviamos una parte de la página hay que añadir en la cabecera de la página que armamos, los estilos que se necesitarán para que la página se vea bien formateada, o también puedes hacer referencia a la hoja de estilos css que corresponde.

2.2.- Otro punto a notar es que estoy añadiendo VerifyRenderingInServerForm para no tener problema con la renderización de algunos controles más complejos como ImageButton, etc.

2.3.- Adicionalmente hay que añadir EnableEventValidation="false" en la directiva de la página aspx, por la misma razón que el punto 2.2.

Continuemos.
Ahora, para recuperar todo el contenido de la actual página ASPX, simplemente modificarías la función para que quede así:

Private Function GetHTML()

Dim stringWrite As System.IO.StringWriter = New System.IO.StringWriter()
Dim htmlWrite As System.Web.UI.HtmlTextWriter = New HtmlTextWriter(stringWrite)

Page.RenderControl(htmlWrite)

Return stringWrite.ToString

End Function

3.- Construyes / reproduces desde el inicio la misma estructura de tu página web,
De manera que una vez enviado no dependas de nada más, osea podrías desconectarte de internet y continuar leyendo tu email con imágenes y demás recursos extraídos de una página web… ya que los recursos se embeben en el correo… y la forma de construir esa estructura HTML especialmente para enviar por correo la puedes ver en este post.

Algunos puntos a tener en cuenta:
  • Si asumimos que las personas tienen internet todo el tiempo… no habría problemas en usar la forma 1 ó 2… más allá de una insignificante demora en la carga del email.
  • Si vas a usar la forma 1 ó 2 todos los recursos que utilize tu página web deben tener rutas absolutas… y no relativas.
Espero que les sea de utilidad.
;)

2 comentarios:

vicro dijo...

interesante articulo, pero unn no me sale, me podrías ayudar con el contenido del
Private Sub SendEmail(ByVal EmailBody As String)
'desde aquí puedes enviar tu email...
End Sub

o tienes alguna versión descargable del código.
atte.

Segundo Serrano dijo...

Hola vicro,

sería algo así:
Public Sub SendEmail(strFrom As String, strTo As String, strSubject As String, strBodyText As String)
Dim Mail As New MailMessage()
Mail.From = New MailAddress(strFrom)
Mail.[To].Add(strTo)
Mail.Subject = strSubject
Mail.Body = strBodyText
Dim SMTPClient As New SmtpClient()
Dim basicAuthenticationInfo As New NetworkCredential("algun_correo1", "algun_password1")
SMTPClient.Host = "algun_email_host"
SMTPClient.UseDefaultCredentials = True
SMTPClient.Credentials = basicAuthenticationInfo

SMTPClient.Send(Mail)

End Sub