Envoyer des emails SMTP/Outlook/MAPI avec Delphi

Ce tutoriel réalisé avec la version 10.1.2 Berlin (Entreprise et Starter) a pour but de montrer plusieurs façons d’envoyer un mail avec Delphi en utilisant les interfaces. Un serveur SMTP, le pilotage d’Outlook avec la technologie OLE qui requiert d’avoir celui-ci installé sur le poste et l’ensemble MAPI seront tour à tour utilisés à cette fin. Pour utiliser ce dernier, un client de messagerie doit être présent.

Les courriers électroniques

Le courrier électronique, courriel, email ou simplement mail est un service de transmission de messages écrits et de documents envoyés électroniquement via un réseau informatique (local ou par Internet), directement dans la boîte aux lettres électronique d’un destinataire.
Il est possible d’envoyer des mails avec Delphi en utilisant différentes méthodes :

  • utiliser un serveur SMTP pour transférer le courrier vers le serveur de messagerie ;
  • piloter Outlook pour écrire et envoyer le message ;
  • utiliser un ensemble standardisé de fonctions, MAPI.

Les sources sont disponibles ici :
http://robin-valtot.developpez.com/sources/vcl_delphi_envoyer_emails.zip

Création du projet

Nous allons créer un nouveau projet Delphi avec une fenêtre appelée uFormEmail. Celle-ci va nous permettre de saisir les données de notre message. Vous pouvez partir directement des sources à télécharger.
email-delphi

Stocker les données

Pour gérer les données d’un mail, nous allons utiliser un enregistrement (record). Celui-ci permet de stocker les données communes des messages.

type
   TDataMessage = record
      SendTo:      string;
      SendCC:      string;
      SendBCC:     string;
      Sender:      string;
      MailObject:  string;
      MailMessage: string;
   end;

Paramétrage

Du paramétrage sera déclaré dans la partie implementation de l’unité pour être visible uniquement à cet endroit. Pour gérer les envois, nous allons avoir besoin de différentes unités référencées dans la clause uses, de constantes qui correspondront à nos boutons radio, ainsi que différents types d’exceptions.

implementation
 
uses
   // SMTP
   IdSMTP, IdExplicitTLSClientServerBase, IdMessage, IdSSLOpenSSL,
   // Outlook
   System.Win.ComObj,
   // MAPI
   Winapi.Mapi,
   Math;
 
type
   TMessageSMTPError    = class(Exception);
   TMessageOutlookError = class(Exception);
   TMessageMAPIError    = class(Exception);
 
const
   // correspondance avec le RadioGroup
   CST_SMTP    = 0;
   CST_OUTLOOK = 1;
   CST_MAPI    = 2;

Les informations de connexions SMTP

Pour envoyer un email avec un serveur SMTP l’adresse de celui-ci est nécessaire de même que le port qui par défaut est le 25. Si Outlook est configuré sur votre poste vous pouvez récupérer le paramétrage depuis votre profil en passant par [Fichier > Paramètres du compte > Modifier]. Les informations sont disponibles sur le site de votre FAI ou du site gérant votre messagerie.

Les différents types de messages

Nous allons avoir plusieurs interfaces. Ces interfaces sont caractérisées par le mot clé interface et un identifiant unique appelé GUID pour permettre le transtypage. La première va servir à envoyer le message, la seconde à retourner le type record ci-dessus, et la dernière à retourner les données supplémentaires pour envoyer avec un serveur SMTP.

   IMessageSender = interface
   ['{E76ABC78-18BF-48C5-9D48-21CDFC56A4C1}']
      /// <summary>pour envoyer un message</summary>
      procedure SendMessage;
   end;
 
   IMessageData = interface
   ['{83D98D4F-45D2-48E1-9C70-23C62EF24014}']
      /// <summary>utilisé pour récupérer les données</summary>
      function GetDataMessage: TDataMessage;
   end;
 
   IMessageDataSMTP = interface
   ['{83D98D4F-45D2-48E1-9C70-23C62EF24014}']
      /// <summary>pour récupérer les données spécifiques à l'envoi smtp</summary>
      procedure SetLogin(const aLogin: string);
      procedure SetPassword(const aPassword: string);
      procedure SetServer(const aServer: string);
      procedure SetPort(const aPort: integer);
      function GetLogin: string;
      function GetPassword: string;
      function GetServer: string;
      function GetPort: integer;
   end;

Le raccourci clavier Ctrl+Maj+G permet de générer automatiquement un GUID.

L’avantage d’utiliser cette méthode est de pouvoir appeler la méthode SendMessage, le type du message n’important pas. Nos prochaines classes vont donc hériter de IMessageSender et de TInterfacedObject. Il est recommandé d’utiliser ce dernier, car c’est un descendant de IInterface : cela signifie qu’il gère automatiquement les références et la gestion mémoire des objets.
Pour rappel, les méthodes d’une interface doivent obligatoirement être déclarées dans les classes descendantes.
Le TDataMessage est obligatoire, c’est pourquoi il est en paramètre du constructeur. La méthode SendMessage est marquée en « virtual abstract ». Le virtual pour laisser les classes descendantes redéfinir la méthode et abstract, car elle n’est pas implémentée dans la classe TMessageSender.

   TMessageSender = class(TInterfacedObject, IMessageSender, IMessageData)
   strict private
      FDataMessage: TDataMessage;
      function GetDataMessage: TDataMessage;
   public
      constructor Create(aDataMessage: TDataMessage);
      procedure SendMessage; virtual; abstract;
 
      property DataMessage: TDataMessage read GetDataMessage;
   end;
 
{ TMessageSender }
 
constructor TMessageSender.Create(aDataMessage: TDataMessage);
begin
   FDataMessage := aDataMessage;
end;
 
function TMessageSender.GetDataMessage: TDataMessage;
begin
   Result := FDataMessage;
end;

Pour le SMTP, nous avons besoin de paramètres supplémentaires. Il s’agit d’un identifiant, d’un mot de passe et des informations du serveur. Pour notre exemple qui ne sert que d’illustration, ces derniers seront renseignés « en dur » dans l’application avec les identifiants d’un compte Office365. La nouvelle classe va supporter l’interface IMessageSender, mais aussi IMessageDataSMTP.

   TMessageSenderSMTP = class(TInterfacedObject, IMessageSender, IMessageData, IMessageDataSMTP)
   strict private
      FDataMessage: TDataMessage;
      FLogin: string;
      FPassword: string;
      FServer: string;
      FPort: integer;
 
      procedure SetLogin(const aLogin: string);
      procedure SetPassword(const aPassword: string);
      procedure SetServer(const aServer: string);
      procedure SetPort(const aPort: integer);
      function GetServer: string;
      function GetPort: integer;
      function GetLogin: string;
      function GetPassword: string;
      function GetDataMessage: TDataMessage;
   public
      constructor Create(aDataMessage: TDataMessage);
      procedure SendMessage; virtual; abstract;
 
      property DataMessage: TDataMessage read GetDataMessage;
      property Login:       string       read GetLogin    write SetLogin;
      property Password:    string       read GetPassword write SetPassword;
      property Server:      string       read GetServer   write SetServer;
      property Port:        integer      read GetPort     write SetPort;
   end;
 
{ TMessageSenderSMTP }
 
constructor TMessageSenderSMTP.Create(aDataMessage: TDataMessage);
begin
   FDataMessage := aDataMessage;
end;
 
function TMessageSenderSMTP.GetDataMessage: TDataMessage;
begin
   Result := FDataMessage;
end;
 
function TMessageSenderSMTP.GetLogin: string;
begin
   Result := FLogin;
end;
 
function TMessageSenderSMTP.GetPassword: string;
begin
   Result := FPassword;
end;
 
function TMessageSenderSMTP.GetPort: integer;
begin
   Result := FPort;
end;
 
function TMessageSenderSMTP.GetServer: string;
begin
   Result := FServer;
end;
 
procedure TMessageSenderSMTP.SetLogin(const aLogin: string);
begin
   FLogin := aLogin;
end;
 
procedure TMessageSenderSMTP.SetPassword(const aPassword: string);
begin
   FPassword := aPassword;
end;
 
procedure TMessageSenderSMTP.SetPort(const aPort: integer);
begin
   FPort := aPort;
end;
 
procedure TMessageSenderSMTP.SetServer(const aServer: string);
begin
   FServer := aServer;
end;

Les classes de base étant créées, nous pouvons créer les classes Mapi, Outlook et SMTP.

   TMessageMapi = class(TMessageSender)
   public
      procedure SendMessage; override;
   end;
 
   TMessageOutlook = class(TMessageSender)
   public
      procedure SendMessage; override;
   end;
 
   TMessageSMTP = class(TMessageSenderSMTP)
   public
      procedure SendMessage; override;
   end;

Elles implémentent uniquement la méthode permettant d’envoyer le message.
Le bouton « Envoyer » va permettre de gérer le curseur, affecter les valeurs dans un TDataMessage et créer le type de message en fonction du mode d’envoi.

procedure TFormEmail.btnEnvoyerClick(Sender: TObject);
var
   SendMessage: IMessageSender;
   DataMessage: TDataMessage;
   Cursor     : TCursor;
begin
   Cursor := Screen.Cursor;
 
   try
      Screen.Cursor := crHourGlass;
 
      try
         DataMessage.SendTo      := edTo.Text;
         DataMessage.SendCC      := edCC.Text;
         DataMessage.SendBCC     := edBCC.Text;
         DataMessage.Sender      := edSender.Text;
         DataMessage.MailObject  := edObject.Text;
         DataMessage.MailMessage := Memo.Text;
 
         case RadioGroup.ItemIndex of
            CST_SMTP :
            begin
               SendMessage := TMessageSMTP.Create(DataMessage);
               (SendMessage as IMessageDataSMTP).SetLogin(edLogin.Text);
               (SendMessage as IMessageDataSMTP).SetPassword(edPassword.Text);
               (SendMessage as IMessageDataSMTP).SetServer('smtp.office365.com');
               (SendMessage as IMessageDataSMTP).SetPort(587);
            end;
            CST_OUTLOOK : SendMessage := TMessageOutlook.Create(DataMessage);
            else
               SendMessage := TMessageMapi.Create(DataMessage);
         end;
 
         SendMessage.SendMessage;
      except
         on E : Exception do
            MessageDlg('Erreur lors de l''envoi de l''email.' + #10#13 + e.Message, mtError, [mbOK], 0);
      end;
   finally
      Screen.Cursor := Cursor;
   end;
end;

La variable SendMessage est déclarée du type de l’interface et peut être de la forme de l’une des trois méthodes d’envoi. Le except permet de gérer les exceptions qui peuvent être signalées durant le processus de création et d’envoi du message.

En fonction de l’option choisie par l’utilisateur, l’envoi sera aiguillé vers la bonne méthode.
Le constructeur est identique pour les différents types. La méthode GetDataMessage permet de récupérer l’enregistrement qui contient les données à travers la propriété DataMessage.

Serveur SMTP

L’une des méthodes les plus rapides est d’utiliser l’envoi des courriers en SMTP (Simple Mail Transfer Protocol) grâce aux composants Indy.
Trois composants sont nécessaires :

  • TIdSMTP : pour se connecter au serveur ;
  • TIdSSLIOHandlerSocketOpenSSL : pour sécuriser les connexions réseau ;
  • TIdMessage : il s’agit de notre message.

Pour utiliser TLS/SSL avec Indy, il faut télécharger les fichiers bibliothèques libeay32.dll et ssleay32.dll disponibles à l’adresse suivante et les copier dans le même répertoire que le fichier exécutable. En fonction de la plate-forme, il faut prendre la version 32 ou 64 bits la plus récente de l’archive openssl :
http://indy.fulgan.com/SSL/
Chez certains serveurs de messagerie, cela est obligatoire (ex. : Google).

Envoyer un message texte

Dans la méthode SendMessage du type TMessageSMTP, il faut créer nos composants Indy.

procedure TMessageSMTP.SendMessage;
var
   IdSMTP    : TIdSMTP;
   IdSSLIO   : TIdSSLIOHandlerSocketOpenSSL;
   IdMessage : TIdMessage;
begin
   inherited;
 
   // création des composants Indy
   IdSMTP    := TIdSMTP.Create(nil);
   IdMessage := TIdMessage.Create(nil);
   IdSSLIO   := TIdSSLIOHandlerSocketOpenSSL.Create(nil);

Nous allons à présent spécifier les valeurs de notre serveur SMTP comme l’adresse, le port (25 par défaut), ainsi que les informations de l’utilisateur si elles sont saisies.

   try
      // adresse et port du serveur SMTP
      IdSMTP.AuthType := satDefault;
      IdSMTP.Host     := Server;
      IdSMTP.Port     := Port;
 
      // utilisation du mode sécurisé (ou pas si l'envoi en anonyme est autorisé)
      if (Login <> '') and (Password <> '') then
      begin
         IdSSLIO.SSLOptions.Method := sslvTLSv1;
         IdSMTP.Username  := Login;
         IdSMTP.Password  := Password;
         IdSMTP.IOHandler := IdSSLIO;
         IdSMTP.UseTLS    := utUseExplicitTLS;
      end;

Nous pouvons maintenant nous connecter au serveur. Si celui-ci ne répond pas, nous allons lever une exception.

      // connexion au serveur
      try
         IdSMTP.Connect;
      except
         on e : Exception do
            raise ESMTPError.Create('Erreur de connexion au serveur SMTP' + #10#13 + e.Message);
      end;

Si la connexion a réussi, nous pouvons nous occuper du message.

      IdMessage.Clear;
 
      // paramétrage de l'expéditeur
      IdMessage.From.Text           := DataMessage.Sender;
      IdMessage.ReplyTo.Add.Address := DataMessage.Sender;
 
      // ajout des destinataires
      if DataMessage.SendTo <> '' then
         IdMessage.Recipients.Add.Address := DataMessage.SendTo;
 
      if DataMessage.SendCC <> '' then
         IdMessage.CCList.Add.Address     := DataMessage.SendCC;
 
      if DataMessage.SendBCC <> '' then
         IdMessage.BccList.Add.Address    := DataMessage.SendBCC;
 
      // objet du message
      IdMessage.Subject := DataMessage.MailObject;
 
      // paramétrage de la date et de la priorité
      IdMessage.Date     := Now;
      IdMessage.Priority := mpNormal;
 
      // il est possible de paramétrer un accusé de lecture
      // idMessage.ReceiptRecipient.Address := adresse de l'expediteur;
 
      // corps du message
      IdMessage.Body.Text := DataMessage.MailMessage;

Nous sommes connectés au serveur SMTP et le message est prêt : nous pouvons l’envoyer.

      try
         IdSMTP.Send(IdMessage);
      except
         on e : Exception do
            raise ESMTPError.Create('Erreur lors de l''envoi de l''email.' + #10#13 + e.Message);
      end;

À la sortie, nous allons fermer la connexion au serveur et libérer les différents composants.

   finally
      IdSMTP.Disconnect;
 
      FreeAndNil(IdSSLIO);
      FreeAndNil(IdMessage);
      FreeAndNil(IdSMTP);
   end;
end;

Envoyer un texte HTML

Il est possible d’envoyer un texte formaté en HTML. Pour cela, nous devons utiliser un TIdText (IdText). Au lieu de spécifier le texte dans la propriété Body.Text du message, voici comment faire :

   IdText := TIdText.Create(IdMessage.MessageParts);
   IdText.Body.Text       := DataMessage.MailMessage; // texte en HTML
   IdText.ContentType     := 'text/html';
   IdText.ContentTransfer := 'quoted-printable';
   IdText.CharSet         := 'utf-8';
   IdMessage.ContentType  := 'multipart/mixed';

Ajouter des pièces jointes

Pour ajouter des pièces jointes à un message, il faut utiliser la propriété MessageParts. Il suffit de créer un TIdAttachementFile, de lui spécifier le message auquel la pièce sera ajoutée, ainsi que le chemin du fichier.

TIdAttachmentFile.Create(IdMessage.MessageParts, 'D:\Fichier.pdf');

Outlook

Il est aussi possible d’envoyer des mails en récupérant ou en créant une instance d’Outlook. Nous allons avoir besoin des constantes utilisées par Outlook : elles seront déclarées localement dans la méthode SendMessage. Pour récupérer Outlook, nous allons créer une fonction GetOutlook qui va nous renvoyer une instance de type OLEVariant.

procedure TMessageOutlook.SendMessage;
const
   // constantes utilisées par Outlook
   // https://msdn.microsoft.com/en-us/library/office/aa219371(v=office.11).aspx
   CSTL_olMailItem        = 0;
   CSTL_olByValue         = 1;
   CSTL_olTo              = 1;
   CSTL_olCC              = 2;
   CSTL_olBCC             = 3;
   CSTL_olEditorWord      = 4;
 
   // constantes issues de Outlook2010.pas
   CSTL_olFormatUnspecified = $00000000;
   CSTL_olFormatPlain       = $00000001;
   CSTL_olFormatHTML        = $00000002;
   CSTL_olFormatRichText    = $00000003;
 
   // fonction permettant de récupérer ou de créer une instance de Outlook
   function GetOutlook(var bFind : boolean) : OLEVariant;
   begin
      bFind  := False;
      Result := Unassigned;
 
      try
         // récupération de la référence vers Outlook
         Result := GetActiveOleObject('Outlook.Application');
         bFind  := True;
      except
         try
            // création d'une nouvelle instance si
            // l'application n'a pas été trouvée
            Result := CreateOleObject('Outlook.Application');
            bFind  := True;
         except
            bFind := False;
         end;
      end;
   end;

Si notre fonction ne retourne aucune instance d’Outlook, nous allons arrêter l’envoi. Sinon nous pouvons continuer et créer le message (ovMailItem) grâce à une variable de type OLEVariant.

var
   ovMailItem      : OLEVariant;
   ovOutlook       : OleVariant;
   bTrouve         : boolean;
   sSignature      : string;
   vDestinataire   : Variant;
begin
   inherited;
 
   try
      ovOutlook := GetOutlook(bTrouve);
 
      if not bTrouve then
      begin
         // si Outlook est fermé ou ouvert en tant que administrateur
         raise EOutlookError.Create('Application Outlook non trouvée.')
      end
      else
      begin
         // création d'un email
         ovMailItem := ovOutlook.CreateItem(CSTL_olMailItem);

Il est possible d’avoir plusieurs comptes paramétrés sur sa messagerie, nous allons utiliser le premier profil et rédiger notre mail en HTML pour conserver la mise en forme de la signature.

         // s'il y a plusieurs profils dans outlook nous allons utiliser le premier
         if ovOutlook.Session.Accounts.Count > 0 then
            ovMailItem.sendUsingAccount := ovOutlook.Session.Accounts.Item(1);
 
         // mise en place du OlBodyFormat (olFormatRichText, olFormatHTML, olFormatPlain)
         // nous allons utiliser le texte html
         ovMailItem.BodyFormat := CSTL_olFormatHTML;

Nous pouvons alors ajouter les destinataires et l’objet.

         // ajout des destinataires
         if DataMessage.SendTo <> '' then
         begin
            vDestinataire      := ovMailItem.Recipients.Add(DataMessage.SendTo);
            vDestinataire.Type := CSTL_olTo;
         end;
 
         if DataMessage.SendCC <> '' then
         begin
            vDestinataire      := ovMailItem.Recipients.Add(DataMessage.SendCC);
            vDestinataire.Type := CSTL_olCC;
         end;
 
         if DataMessage.SendBCC <> '' then
         begin
            vDestinataire      := ovMailItem.Recipients.Add(DataMessage.SendBCC);
            vDestinataire.Type := CSTL_olBCC;
         end;
 
         // ajouter un accusé de lecture
         // ovMailItem.ReadReceiptRequested := True;
 
         ovMailItem.Subject := DataMessage.MailObject;

Il existe une astuce pour récupérer la signature présente dans Outlook, si l’utilisateur a choisi de l’ajouter automatiquement aux nouveaux messages. Nous allons ouvrir le message, mais sans le rendre visible, puis nous pourrons récupérer le code HTML de la fenêtre.

         // il est possible d'ouvrir le message sans l'afficher
         // ceci permet par exemple de récupérer la signature
         // de l'utilisateur si elle est ajoutée automatiquement
         ovMailItem.Display(False);
 
         // récupération de la signature (s'il y en a une)
         sSignature := ovMailItem.HTMLBody;
 
         // concaténation du texte du message et de la signature
         ovMailItem.HTMLBody := DataMessage.MailMessage + sSignature;

Il ne reste plus qu’à envoyer le message.

         // il est possible d'afficher l'email avant de l'envoyer avec ovMailItem.Display;
         ovMailItem.Send;
      end;
   finally
      ovMailItem := Unassigned;
   end;
end;

Il est possible d’afficher le mail et de laisser l’utilisateur l’envoyer lui-même en utilisant la procédure Display.

Ajouter des pièces jointes

Pour ajouter des documents sur un mail, nous allons utiliser notre constante CST_olByValue et la fonction Add qui prend en paramètres :
Source : le chemin vers le fichier ;

  • Type : 1 pour indiquer qu’il s’agit d’une copie du fichier d’origine (et non une référence) ;
  • Position : 0 la pièce jointe est masquée, 1 la pièce doit être en début du corps du message, supérieure à 1 elle sera à la fin ;
  • DisplayName : le nom de la pièce jointe.
ovMailItem.Attachments.Add('D:\fichier.doc', CST_olByValue, 1, 'D:\fichier.doc');

MAPI

Pour utiliser un envoi MAPI, il faut avoir un client de messagerie sur le poste. L’utilisation est conditionnée à sa disponibilité et à son paramétrage.

Utiliser MAPI

Nous allons créer plusieurs variables. MapiDest sera initialisée à nil.

procedure TMessageMapi.SendMessage;
var
   MapiMessage    : TMapiMessage;
   MapiDest       : PMapiRecipDesc;
   MapiExpediteur : TMapiRecipDesc;
   MAPI_Session   : Cardinal;
   MapiResult     : Cardinal;
   MAPIError      : DWord;

MapiMessage et MapiExpediteur seront paramétrées avec les données du DataMessage.

begin
   inherited;
 
   MapiDest := nil;
 
   try
      // FillChar permet de remplir une suite d'octets avec une valeur, ici 0
      FillChar(MapiMessage, Sizeof(TMapiMessage), 0);
      MapiMessage.lpszSubject  := PAnsiChar(AnsiString(DataMessage.MailObject));
      MapiMessage.lpszNoteText := PAnsiChar(AnsiString(DataMessage.MailMessage));
 
      // même traitement pour paramétrer l'expéditeur
      FillChar(MapiExpediteur, Sizeof(TMapiRecipDesc), 0);
      MapiExpediteur.lpszName    := PAnsiChar(AnsiString(DataMessage.Sender));
      MapiExpediteur.lpszAddress := PAnsiChar(AnsiString(DataMessage.Sender));
      MapiMessage.lpOriginator   := @MapiExpediteur;

Pour les destinataires, il faut initialiser le nombre de destinataires avant l’affectation.

      // paramétrage du nombre de destinataires
      MapiMessage.nRecipCount := IfThen(DataMessage.SendTo <> '', 1) + IfThen(DataMessage.SendCC <> '', 1) + IfThen(DataMessage.SendBCC <> '', 1);
      // et allocation de la mémoire nécessaire
      MapiDest                := AllocMem(SizeOf(TMapiRecipDesc) * MapiMessage.nRecipCount);
      // paramétrage des destinataires sur notre message MAPI
      MapiMessage.lpRecips    := MapiDest;
 
      if DataMessage.SendTo <> '' then
      begin
         MapiDest.lpszName     := PAnsiChar(AnsiString(DataMessage.SendTo));
         MapiDest.ulRecipClass := MAPI_TO;
      end;
 
      if DataMessage.SendCC <> '' then
      begin
         MapiDest.lpszName     := PAnsiChar(AnsiString(DataMessage.SendCC));
         MapiDest.ulRecipClass := MAPI_CC;
      end;
 
      if DataMessage.SendBCC <> '' then
      begin
         MapiDest.lpszName     := PAnsiChar(AnsiString(DataMessage.SendBCC));
         MapiDest.ulRecipClass := MAPI_BCC;
      end;

MapiLogon permet d’établir une connexion avec le client de messagerie et MapiSendMail sert à envoyer le message.

      // pour ajouter un accusé de lecture
      // MapiMessage.flFlags :=  MAPI_RECEIPT_REQUESTED;
 
      // pour ajouter des pièces jointes avec Fichier une variable de type PMapiFileDesc
      // qui est initialisée à nil au début de cette procédure
      // MapiMessage.nFileCount   := iNombreDeFichierAJoindre;
      // Fichier                  := AllocMem(SizeOf(TMapiFileDesc) * MapiMessage.nFileCount);
      // Fichier.nPosition        := 0;
      // Fichier.lpszPathName     := PAnsiChar(AnsiString(email.ListePieceJointe[iCompte].sCheminDoc));
      // MapiMessage.lpFiles      := Fichier;
 
      // récupération du client de messagerie
      MapiResult := MapiLogon(0, PAnsiChar(''), PAnsiChar(''), MAPI_LOGON_UI or MAPI_NEW_SESSION, 0, @MAPI_Session);
 
      if (MapiResult = SUCCESS_SUCCESS)then
      begin
         // nous pouvons envoyer le message
         MAPIError := MapiSendMail(0, 0, MapiMessage, MAPI_DIALOG or MAPI_LOGON_UI or MAPI_NEW_SESSION, 0);
 
         // liste des erreurs en MAPI : http://support.microsoft.com/kb/119647
         if MAPIError = SUCCESS_SUCCESS then
            ShowMessage('Message envoyé avec MAPI.')
         else
            raise EMAPIError.Create('Erreur MAPI avec le code ' + MapiResult.ToString + '.');
      end
      else
      begin
         raise EMAPIError.Create('Erreur MAPI avec le code ' + MapiResult.ToString + '.');
      end;
   finally
      MapiLogOff(MAPI_Session, 0, 0, 0);
      FreeMem(MapiDest);
   end;
end;

Accusé de réception

Lors de l’envoi d’un message, nous pouvons demander un accusé de réception.

MapiMessage.flFlags :=  MAPI_RECEIPT_REQUESTED;

Ajouter une pièce jointe

Pour ajouter une pièce jointe, nous avons besoin d’une variable PMapiFileDesc. Pour réaliser le paramétrage de celle-ci, il faut indiquer le nombre de pièces à joindre.

      MapiMessage.nFileCount   := iNombreDeFichierAJoindre;
      Fichier                  := AllocMem(SizeOf(TMapiFileDesc) * MapiMessage.nFileCount);
      Fichier.nPosition        := 0;
      Fichier.lpszPathName     := PAnsiChar(AnsiString(CheminDocJoint));
      MapiMessage.lpFiles      := Fichier;

Conclusion

Dans les applications, le SMTP est plus répandu que le MAPI, chaque méthode ayant ses avantages et ses inconvénients : ce sera à vous de choisir celle qui sera la plus adaptée à vos besoins.
La méthode SMTP permet d’envoyer rapidement les mails vers le serveur. En revanche, aucune copie des mails n’est sauvegardée. Il faut être en CC ou CCI pour garder une trace. Ce mode indépendant du client de messagerie permet d’envoyer des mails depuis une application sans configurer chacun des postes utilisateurs.
En MAPI (dont Outlook), il est possible d’envoyer et de recevoir des mails. Les envois sont enregistrés dans les messages envoyés et la plupart des clients fonctionnent même en hors-ligne en gérant une boîte d’envoi. Ce type de fonctionnement est moins répandu que le premier et la sécurité des clients de messagerie peut être un frein : il n’est pas rare de voir un popup apparaître lors de l’envoi d’un message depuis une application externe.
Quel que soit votre choix, vous avez vu que Delphi savait y répondre !

Remerciements

Je remercie la communauté Delphi du forum, en particulier gvasseur58 pour son soutien et son aide pour la création et la correction de ce tutoriel, gaby277 pour ses remarques très constructives, didier.cabale pour son expertise technique ainsi que ClaudeLELOUP pour la relecture orthographique.

Une réaction au sujet de « Envoyer des emails SMTP/Outlook/MAPI avec Delphi »

  1. Marion Candau Réponse

    Merci pour ce tutoriel très bien rédigé et instructif. J’ai deux questions :
    – Dans mon client de messagerie (Thunderbird), j’ai deux adresses mails: email1@societe.com et email2@societe.com. Si je mets email2@societe.com comme expéditeur du mail et que j’utilise MAPI, il me met quand même email1@societe.com comme expéditeur. Il y a un moyen de modifier ça dans le code ?
    – Si j’ai une adresse mail quelconque, est-ce qu’il y a un moyen de savoir si elle est enregistrée dans le client de messagerie (comme expéditeur) avec MAPI ou non ?
    Merci d’avance,
    Marion

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*