Envoyer des mails avec Delphi

Robin Valtot

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. 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.

Commentez

- Titre : Envoyer des mails avec Delphi

- Auteur : Robin Valtot

- Parution : 18 mars 2017

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2017 Robin Valtot. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Les courriers électroniques

- II. Création du projet

- III. Stocker les données

- IV. Paramétrage

- V. Les informations de connexions SMTP

- VI. Les différents types de messages

- VII. Serveur SMTP

- VII-A. Envoyer un message texte

- VII-B. Envoyer un texte HTML

- VII-C. Ajouter des pièces jointes

- VIII. Outlook

- VIII-A. Mise en place

- VIII-B. Ajouter des pièces jointes

- IX. MAPI

- IX-A. Utiliser MAPI

- IX-B. Accusé de réception

- IX-C. Ajouter une pièce jointe

- X. Conclusion

- XI. Remerciements

I - 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 :

- https://robin-valtot.developpez.com/sources/vcl_delphi_envoyer_emails.zip

II - 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.

III - 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;

IV - 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;

V - 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.

VI - 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.

VII - 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).

VII-A - 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;

VII-B - 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';

VII-C - 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');

VIII - Outlook

VIII-A - Mise en place

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.

VIII-B - 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');

IX - 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.

IX-A - 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;

IX-B - Accusé de réception

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

MapiMessage.flFlags :=  MAPI_RECEIPT_REQUESTED;

IX-C - 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;

X - 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 !

XI - 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, Joc02 pour son aide ainsi que ClaudeLELOUP pour la relecture orthographique.