La clase TIdMessageBuilderHtml y el envío de correos HTML desde Delphi

Hay muchas formas de enviar correos con Delphi.

Mi preferida desde hace tiempo es hacerlo vía SMTP con la clase TIdSMTP, que es flexible y poderosa.

Hoy, a raíz de que mi estimado amigo, Edgar Ramírez, publicara su artículo Enviar correo con imágenes incrustadas con Delphi he recordado que hace tiempo me gustaría iniciar una serie de artículos sobre el uso de INDY y la comunicación TCP/IP con Delphi.

A manera de respuesta a la publicación citada, quiero mostrar cómo realizar el envío de un correo similar —con una imagen incrustada— haciendo uso de la clase auxiliar TIdMessageBuilderHtml, que en mi opinión no solo facilita las cosas sino que nos deja una solución mucho más elegante y fácil de entender en el código.

La parte relevante del envío de correo es:

<br>
procedure TfrmCorreo.EnviaCorreoImagen(const FileName: string);<br>
var<br>
  Builder: TIdMessageBuilderHtml;<br>
  Msg: TIdMessage;<br>
  SMTP: TIdSMTP;<br>
begin<br>
  Builder := TIdMessageBuilderHtml.Create;<br>
  try<br>
    Builder.Html.Add('&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;Una imagen para ti&lt;/TITLE&gt;&lt;/HEAD&gt;&lt;BODY&gt;');<br>
    Builder.Html.Add('&lt;p&gt;&lt;strong&gt;Una imagen para ti&lt;/strong&gt;&lt;/p&gt;');<br>
    Builder.Html.Add('&lt;div&gt;');<br>
    Builder.Html.Add('  &lt;img border="0" src="cid:laimagen" &gt;');<br>
    Builder.Html.Add('&lt;/div&gt;');<br>
    Builder.PlainText.Add('Este correo contiene una imágen para ti. '<br>
      + 'Debes usar un visor HTML para verla');<br>
    Builder.HtmlFiles.Add(FileName, 'laimagen');<br>
    Msg := Builder.NewMessage();<br>
    try<br>
      Msg.Recipients.EMailAddresses := eRecipients.Text;<br>
      Msg.From.Name := eFromName.Text;<br>
      Msg.From.Address := eFromEmail.Text;<br>
      Msg.Subject := 'Una imagen para ti';<br>
      SMTP := TIdSMTP.Create;<br>
      try<br>
        SMTP.Host := eSMTPHost.Text;<br>
        SMTP.Username := eSMTPUser.Text;<br>
        SMTP.Password := eSMTPPass.Text;<br>
        SMTP.Connect;<br>
        try<br>
          SMTP.Send(Msg);<br>
        finally<br>
          SMTP.Disconnect;<br>
        end;<br>
      finally<br>
        SMTP.Free;<br>
      end;<br>
    finally<br>
      Msg.Free;<br>
    end;<br>
  finally<br>
    Builder.Free;<br>
  end;<br>
end;<br>

Como puede observarse, la instancia de TIdMessageBuilderHtml se encarga de los detalles sobre adjuntar los archivos. De lo que debemos asegurarnos es de proveer un cid diferente para cada imagen incluida en el HTML de nuestro correo, y que estos identificadores se correspondan con los archivos incluidos posteriormente en la llamada al método HtmlFiles.Add, que recibe como parámetros el nombre del archivo y el cid correspondiente.

Aclaración: En mi opinión cualquier método con más de 25 líneas de código es demasiado grande y debe considerarse su refactorización. Es el caso del código publicado, sin embargo he preferido mantener un solo método para no enredar al lector con tener que seguir mentalmente las llamadas entre ellos. Como se ve, el método se encarga de todo el envío del correo, lo cuál conceptualmente también puede ser mucho para un solo método. En algo para producción, esto probablemente sería dividido en 3 distintos métodos: armar el correo HTML, configurar el mensaje y finalmente la conexión/envío/desconexión.

Editado el 1/7/2021

La unidad a incluir en la cláusula uses es IdMessageBuilder. Lo agrego aquí, porque sin querer he omitido la información en la entrada y hay varios comentarios de algunas personas que no encuentran la clase. La unidad está en la carpeta Protocols de Indy.

INDY: Finalmente se hizo el merge del branch Tiburon en el trunk

Indy Sockets, la popular biblioteca de clases para programación TCP/IP que viene con Delphi, finalmente ha completado el merge del branch Tiburon de regreso al trunk.

Si no estás familiarizado con la terminología del control de versiones, particularmente SubVersion, lo que esto significa es que el código fuente, que alguna vez se ramificó del desarrollo principal (branch), para soportar el cambio a Unicode en los tiempos de Delphi 2009 (llamado Tiburon), finalmente ha sido llevado de regreso (merge) a la raíz del desarrollo (trunk).

No es que hasta ahora se terminara de portar el código… en realidad es que luego de realizar las adaptaciones necesarias, quién sabe por qué, el equipo de INDY siguió desarrollando en el branch y el código nunca se integró de vuelta. Ahora lo hacen, en parte, porque estamos próximos a ver el inicio del desarrollo de INDY 11 (probablemente otro release que romperá la compatibilidad con el código existente).

En conclusión

  • Si obtenés el código de INDY directamente de SVN, deberás configurar el cliente para que obtenga el código de trunk y no de branches/tiburon, como lo haces ahora
  • Si obtenés el código de INDY descargando el ZIP del mirror, ahora debes descargar el archivo Indy10_xxxx.zip y no el Indy10Tiburon_xxx.zip
  • Si aún compilas con versiones viejas de SVN, mi consejo es que lo actualicés y te hagás a la idea que es buena idea mantenerlo actualizado 😉

Como es costumbre en INDY, la documentación oficial (incluyendo el sitio de descarga) aún no refleja esta información, y será actualizada pronto.

Vía anuncios de Remy Lebeau en foros Embarcadero y foros Atozed Software