Delphi

Email con allegati e immagini incorporate usando i componenti Indy

calendar_today personTeam EGSOFT schedule4 min di lettura
info

Disclaimer: le informazioni pubblicate in questa sezione hanno finalità di pura divulgazione tecnica. EG Software S.r.l. non si assume alcuna responsabilità per un utilizzo improprio dei contenuti, né per eventuali danni diretti o indiretti derivanti dalla loro applicazione, e non garantisce l'aggiornamento, l'accuratezza o la completezza delle informazioni riportate. Prima di utilizzare in produzione codice o procedure qui descritte, verificane sempre l'adeguatezza al proprio contesto.

I componenti Indy (TIdSMTP, TIdMessage) restano la via più diretta per inviare email da un'applicazione Delphi senza dipendenze esterne. La parte meno intuitiva non è la connessione SMTP in sé, ma la costruzione del messaggio quando servono sia allegati tradizionali sia immagini mostrate direttamente nel corpo HTML: per queste ultime serve un Content-ID che leghi l'allegato al tag <img> che lo referenzia.

La classe di invio

Incapsulare l'invio in una classe dedicata evita di sparpagliare la configurazione SMTP (host, porta, credenziali) tra i vari form da cui si spediscono email.

unit uEmailSender;

interface

uses
  System.SysUtils, IdSMTP, IdMessage, IdAttachmentFile, IdText, IdExplicitTLSClientServerBase;

type
  TEmailSender = class
  private
    FSMTPHost: string;
    FSMTPPort: Integer;
    FUsername: string;
    FPassword: string;
    procedure AddAttachment(const FileName: string; AMessage: TIdMessage);
    procedure AddEmbeddedImage(const FileName, ContentID: string; AMessage: TIdMessage);
  public
    constructor Create(const SMTPHost: string; SMTPPort: Integer;
      const Username, Password: string);
    procedure SendEmail(const Recipient, Subject, Body: string;
      const AttachmentFile: string = ''; const ImageFile: string = '');
  end;

implementation

constructor TEmailSender.Create(const SMTPHost: string; SMTPPort: Integer;
  const Username, Password: string);
begin
  FSMTPHost := SMTPHost;
  FSMTPPort := SMTPPort;
  FUsername := Username;
  FPassword := Password;
end;

procedure TEmailSender.AddAttachment(const FileName: string; AMessage: TIdMessage);
begin
  if FileExists(FileName) then
    TIdAttachmentFile.Create(AMessage.MessageParts, FileName);
end;

Immagini incorporate nel corpo HTML

Per un'immagine visibile direttamente nel testo (un logo in intestazione, ad esempio) l'allegato riceve un ContentID e il corpo HTML lo referenzia con src="cid:...".

procedure TEmailSender.AddEmbeddedImage(const FileName, ContentID: string; AMessage: TIdMessage);
var
  Attachment: TIdAttachmentFile;
  TextPart: TIdText;
begin
  if not FileExists(FileName) then
    Exit;

  Attachment := TIdAttachmentFile.Create(AMessage.MessageParts, FileName);
  Attachment.ContentID := ContentID;

  TextPart := TIdText.Create(AMessage.MessageParts, nil);
  TextPart.ContentType := 'text/html';
  TextPart.CharSet := 'utf-8';
  TextPart.Body.Text :=
    'Logo';
end;

procedure TEmailSender.SendEmail(const Recipient, Subject, Body: string;
  const AttachmentFile: string; const ImageFile: string);
var
  SMTP: TIdSMTP;
  Message: TIdMessage;
begin
  SMTP := TIdSMTP.Create(nil);
  Message := TIdMessage.Create(nil);
  try
    SMTP.Host := FSMTPHost;
    SMTP.Port := FSMTPPort;
    SMTP.Username := FUsername;
    SMTP.Password := FPassword;

    Message.From.Address := FUsername;
    Message.Recipients.Add.Address := Recipient;
    Message.Subject := Subject;
    Message.Body.Text := Body;

    if AttachmentFile <> '' then
      AddAttachment(AttachmentFile, Message);
    if ImageFile <> '' then
      AddEmbeddedImage(ImageFile, 'logoAziendale', Message);

    SMTP.Connect;
    try
      SMTP.Send(Message);
    finally
      SMTP.Disconnect;
    end;
  finally
    SMTP.Free;
    Message.Free;
  end;
end;

end.

Un paio di accorgimenti pratici

Le credenziali SMTP (host, utente, password) vanno sempre lette da configurazione — mai scritte nel codice — e idealmente protette come descritto altrove per i file INI. Vale anche la pena avvolgere SMTP.Connect e SMTP.Send in un blocco che intercetta EIdSocketError ed EIdSMTPException separatamente dalle altre eccezioni, così da distinguere un problema di rete da un rifiuto del server (autenticazione, mittente non valido) e mostrare all'utente un messaggio realmente utile.

Altri articoli su Delphi grid_viewTutte le tematiche
Scrivici su WhatsApp