menu
  Home  ==>  articles  ==>  web  ==>  indy_pop3_client_server   

Indy POP3 Client / Server (email) - John COLIBRI.

  • résumé : lecteur de mails : un exemple simple d'un serveur et d'un lecteur d'email Indy : les instructions de démarrage / connexion, les commandes POP3, l'affichage de la lecture de mails
  • mots clé : POP3 - lecture de mail - serveur POP3 - lecteur POP3 - affichage Indy Vcl - tidSync - tIdPop3 - tIdPop3Server - LIST RETR DELE
  • logiciel utilisé : Windows XP personnel, Delphi 2006, Indy 9
  • matériel utilisé : Pentium 2.800 Mhz, 512 Meg de mémoire, 250 Giga disque dur
  • champ d'application : Delphi 6, Delphi 7, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi XE,
  • niveau : développeur Delphi
  • plan :


1 - Lecture et Ecriture de Mails

Cet article présente des projets pour lire des email en utilisant Indy.

Internet a décomposé la gestion des emails en deux parties

  • la partie SMTP (Simple Mail Transfer Protocol) qui gère
    • l'envoi d'un courriel depuis votre PC (le Client SMTP)
    • la réception de ces données sur un serveur distant (le Serveur SMTP).
    Chaque fois que vous envoyez un mail, vous utilisez un client SMTP. Ce mail est envoyé vers une poste serveur, où un Serveur SMTP passe son temps à recevoir vos mail (et ceux des autres utilisateurs de ce serveur) et à les archiver. Cet archivage n'est pas régi par des règles Internet, et chaque serveur (Wanadoo / Orange, Free, Club Internet, mon propre serveur qui gère les mails que vous nous envoyez sur jcolibri@jcolibri.com) est libre de stocker les mails à sa façon.

    Le poste serveur sert donc essentiellement à stocker les mails envoyés. La partie SMTP s'occupe de les recevoir et de les archiver, en attente d'une éventuelle lecture.

    Ceci peut être représenté ainsi :

    sending_mail_smtp

  • la partie POP3 (Post Office Protocol 3) qui gère
    • la lecture d'un mail depuis votre PC (le Client POP3)
    • la recherche du mail sur le disque du serveur de mail, et son envoi à celui qui l'a demandé (le Client POP3)
    La partie POP3 sert donc simplement à rechercher sur le serveur les mails qui quelqu'un a stocké sur le poste serveur à notre attention et à nous les faire parvenir via Internet

    Ce que nous pouvons illustrer comme suit:

    reading_mail_pop3



Ces envois et lectures de mail sont en général effectués depuis des outils tels que Outlook Express, mais vous pouvez, avec avantage, créer vos propres clients SMTP et POP3:
  • votre client SMTP pourra, par exemple, intégrer une mécanique de fond de page ou tout autre traitement sur mesure (archivage, cryptage etc) avant l'envoi vers le serveur SMTP
  • votre client POP2 pourra mettre en place des filtrages de spam très perfomant, des organisation de stockages plus élaborées qu'Outlook, une gestion plus facile de la lecture des mails et pièces jointes
Il est plus rare de mettre en place des serveurs SMTP ou POP3, car cela impose l'utilisation et la mise en place d'un IP connu de vos interlocuteurs (Ip dynamique ou Ip fixe), et n'a de raison d'être que si vous ne souhaitez pas utiliser les serveurs commerciaux usuels. Pour info, c'est ce que nous avons fait pour pouvoir avoir un mail "jcolibri@jcolibri.com", plutôt que "jcolibri@free.fr"



Bien qu'il soit rare d'avoir à mettre en place à la vois un client et un serveur SMTP, ou un client et un serveur POP3, nous allons dans cet article au contraire présenter les deux interlocuteurs. Ceci permet

  • de mettre au point le fonctionnement des deux côtés. Même si vous ne souhaitez écrire que le Client Pop3, par exemple, l'utilisation de votre propre Serveur Pop3 pourra être utilisé pour la mise au point et le réglage de votre Client
  • de mieux comprendre le protocole POP3 ou SMTP
Nous avons choisi pour cet article d'examiner la partie POP3.




2 - Le Protocole POP3

2.1 - Les Commandes

Le protocole prévoit un certain nombre de commandes:
  • le client envoie le nom de la commande suivi de paramètres éventuels
  • le serveur renvoie sa réponse. La réponse débute par "+OK" ou "-ERR", suivi de données éventuelles
Voici les commandes du protocole POP3:



2.2 - USER <username>

   le Client POP3 envoie l'identificateur pour authentification
<username> est l'adresse e-mail du client
   le Serveur POP3 répond. En général, le serveur renvoie toujours "+OK", même si le nom est incorrect (pour éviter les avalanches de spam)
Exemple

 
    USER jcolibri@jcolibri.com
    +OK
 



2.3 - PASS <password>

   le Client POP3 envoie son mot de passe. Cette commande est envoyée juste après USER
Exemple:

 
    PASS xyz
    +OK
 



2.4 - STAT

   le Client POP3 envoie STAT
   le Serveur POP3 retourne le nombre de messages et le nombre total d'octets
Exemple:

 
    STAT
    +OK 55 67232
 



2.5 - LIST

   le Client POP3 envoie LIST
   le Serveur POP3 retourne
  • le nombre de messages et le nombre d'octets
  • la liste des numéros de chaque message et leur taille
  • un point sur une ligne
Exemple:

 
    LIST
    +OK 4 1486665
    1 976
    2 977
    3 975
    4 1483737
    .
 

Il est possible de demander les statistiques d'un numéro de message particulier, avec une réponse négative s'il n'existe pas



2.6 - RETR <messages number>

   le Client POP3 envoie RETR et un numéro de message
   le Serveur POP3
  • retourne
    • +OK
    • le message complet (en-tête, ligne blanche, contenu) au format MIME
    • un point sur une ligne
Exemple:

 
    RETR 3
    +OK 235 octets
    From: "felix" <huckleberry@free.fr>
    To: <jcolibri@jcolibri.com>
    Subject: test
    Date: Mon, 18 Jan 2010 19:32:02 +0100
    
    Ceci est un test
    .
 



2.7 - DELE <message number>

   le Client POP3 envoie DELE et un numéro de message
   le Serveur POP3
  • marque le message comme devant être effacé après QUIT
  • retourne +OK (plus un texte éventuel) ou une erreur
Exemple:

 
    DELE 3
    +OK message 3 deleted
 



2.8 - RSET

Cette commande est optionnelle.
   le Client POP3 envoie RSET
   le Serveur POP3 retourne +OK (plus un texte éventuel) et réinitialise la session :
  • les messages marqués pour effacement ne sont plus marqués
Exemple:

 
    RSET
    +OK
 



2.9 - TOP <message number> [<number of lines>]

Cette commande est optionnelle
   le Client POP3 envoie TOP, le numéro de message, et optionnellement le nombre de lignes à retourner
   le Serveur POP3 retourne
  • le status
  • l'en-tête du message
  • si un nombre de lignes est spécifié, seul ces lignes du contenu sont retournées
Cette commande permet d'avoir une idée du contenu du message, sans le transférer en entier

Exemple:

 
    TOP 2 3
    +OK
    [headers of message 2]
    -------=_Part_7245_2349853.2340985098374
    Content-Type: text/plain; charset=ISO-8859-1
    Content-Transfer-Encoding: 7bit
    .
 



2.10 - UIDL [<message number>]

Cette commande est optionnelle
   le Client POP3 envoie UIDL et, optionnellement un numéro de message
   le Serveur POP3 retourne
  • le status
  • la liste des numéros de message et leur identifiant
Exemple:

 
    UIDL
    +OK
    1 4239F2D2DED94A21A801F4A14796B0C0
    2 16CAE91D6A9B488E89587A225EAC8F3E
    3 A7FE63D715B849489B3EE60903AD9E94
    4 83CA8D76A6EB4229B6D6F501BABCFD13
    .
 



2.11 - QUIT

   le Client POP3 envoie QUIT
   le Serveur POP3 répond et efface les messages marqués pour effacement
Exemple:

 
    QUIT
    +OK GOODBYE
 



2.12 - Autres commandes

POP3 contient quelques autres commandes non essentielles
  • NOOP : opération blanche
  • APOP, qui est une autre commande d'authentification


2.13 - Une session

Voici un exemple de session

 
    le serveur est lancé et attend les clients sur le port 110
 
    notre client se connecte
    +OK POP3 server ready <1896.697170952@dbc.mtview.ca.us>
 
    USER jcolibri@jcolibri.com
    +OK
 
    PASS xyz
    +OK
 
    LIST
    +OK 4 1486665
    1 976
    2 977
    3 235
    4 1483737
    .
 
    RETR 3
    +OK 235 octets
    From: "felix" <huckleberry@free.fr>
    To: <jcolibri@jcolibri.com>
    Subject: test
    Date: Mon, 18 Jan 2010 19:32:02 +0100
    
    Ceci est un test
    .
 
    DELE 3
    +OK message 3 deleted
 
    QUIT
    +OK GOODBYE maildrop has 3 messages (320 octets)
 
    le client se déconnecte
    le serveur gère les autres clients
 




3 - Le serveur POP3 Indy et le client POP3 Indy

3.1 - Serveur POP3 Indy : tIdPop3Server

Voici le diagramme de classe UML de tidPop3Server

tidpop3server



Et:

  • tIdPop3Server n'a qu'une propriété, DefaultPort, qui est en général 110
  • tidPop3Server a un événement par commande principale. Chacune de ces commandes a un paramètre tIdCommand, qui donne accès à tIdPeerThread qui donne accès à tIdConnection.
  • un descendant de tIdPeerThread contient les données pour gérer l'authentification (CheckUser)
  • tIdPop3Server génère des événements après chaque réception de commande Pop3 du client, et c'est dans ces événements que nous sommes censés gérer les données qui sont stockés sur le serveur: nombre de mails, taille, liste, renvoi, effacement etc


Donc :
  • lorsque le Serveur reçoit une connexion, il crée un tidPop3ServerThread qui va dialoguer avec ce client pour gérer la lecture de ses mails. Cet objet
    • a accès au socket pour lire et écrire (Connection)
    • contient les champs UserName et PassWord
  • le Serveur reçoit les commandes USER et PASS et garnit les champls UserName et PassWord de tIdPop3ServerThread.
    Il déclenche l'événement CheckUser que nous pouvons utiliser pour effectuer nos filtrages.
  • si nous avons accepté le message, nous utilisons tIdPop3Server.OnRETR pour chercher le texte du message et l'envoyer, en utilisant, par exemple, une succession de WriteLn


3.2 - Fonctionnement client tIdPop3

Voici le diagramme de classe UML du client tIdPop2 :

tidpop3

tIdPop3Client permet simplement d'envoyer des commandes Pop3 (avec les paramètres spécifiés), et de recevoir les réponses.

  • pour nous connecter, nous initialisons Host, UserName, PassWord
    et appellons Connect
  • nous envoyons les différentes commandes Pop3 en utilisant IdPop3.SendCmd, et les réponses éventuelles sont récupérées sous forme de tStrings comme paramètre de tIdPop3.Capture
  • pour RETR, nous utilisons la procédure tIdPop3.Retrieve, qui retourne le mail dans un tIdMessage que nous fournissons comme paramètre


3.3 - Démonstration tIdPop3, tIdPop3Server

Pour notre démonstration
  • côté Serveur
    • posez un tIdPop3Server
    • posez un bouton "start" et un bouton "stop" qui basculent Active
    • créez les événements CheckUser, OnLIST, OnRETR, OnDELE (code ci-dessous)
  • côté Client
    • posez un client tIdPop3, initialisez Host, UserName, PassWord
    • posez un tIdAntiFreeze et un tIdMessage
    • posez des boutons pour connecter et déconnecter
    • posez un bouton "list" et écrivez le code pour envoyer la commande et récupérer la liste des messages (code ci-dessous)
    • posez un bouton "retrieve", demandez et récupérez un message
    • idem pour "delete"


3.4 - Scénario Pop3 Indy

Un scénario Pop3 serait par exemple le suivant
   IdPop3Server1 est démarré (IdPOP3Server1.Active basculé à True)
   IdPop3Client1 initialise
  • Host (127.0.0.1)
  • UserName (my_user)
  • PassWord (my_pass)
et appelle Connect
   IdPop3Server1 déclenche CheckUser, et, après vérification, nous acceptons ou refusons cet utilisateur :

Procedure TForm1.IdPOP3Server1CheckUser(AThreadTIdPeerThread;
    LThreadTIdPOP3ServerThread);
  Begin
    If (LThread.Username ... ) And (LThread.Password ...)
      Then LThread.State:= Trans;
  End// IdPOP3Server1CheckUser

   IdPop3Client1 demande la liste des mails non lus:

Procedure TForm1.list_Click(SenderTObject);
  Begin
    With IdPop31 Do
      If SendCmd('LIST')= wsOk
        Then Capture(ListBox1.Items);
  End// list_Click

   IdPop3Server1 déclenche OnLIST, où nous retournons la liste et les numéros des messages (ici abrégé)

Procedure TForm1.IdPOP3Server1LIST(ASenderTIdCommandAMessageNumInteger);
  Begin
    ASender.Thread.Connection.WriteLn('+OK 'IntToStr(Count)+ ' 120');
    For l_file_index:= 0 To Count- 1 Do
      ASender.Thread.Connection.WriteLn(IntToStr(1+ l_file_index)+ ' 40');
  End;

   IdPop3Client1 demande la réception d'un message ayant un numéro donné dans IdMessage1 :

Procedure TForm1.retrieve_Click(SenderTObject);
  Begin
    IdPop31.Retrieve(3, IdMessage1);

et attend la réponse du serveur

   IdPop3Server1 déclenche OnRETR, et utilise le numéro de message pour le chercher et le retourner à l'expéditeur (ici simplifié)

Procedure TForm1.IdPOP3Server1RETR(ASenderTIdCommandAMessageNumInteger);
  Var l_c_messagetStringList;
  Begin
    l_c_message:= tStringList.Create;
    l_c_message.LoadFromFile(ExtractFilePath(Application.ExeName)
        + '\_data_pop3\'IntToStr(aMessageNum)+ '.txt');

    With ASender.Thread.Connection Do
    Begin
      WriteLn('+OK 'IntToStr(Length(l_c_message.Text))+ ' octets');
      WriteLn(l_c_message.Text);

      WriteLn('.');
    End;
    l_c_message.Free;
  End// IdPOP3Server1RETR

   IdPop3Client1 reprend le contrôle après l'appel à RETR, et utilise le message qui a été déposé et analysé par IdMessage1 :

    With IdMessage1 Do
    Begin
      display('From 'From.Text);
      With Recipients.Items[0] Do
        display('To   'Name' 'Address);
      display('Subject   'Subject);
      display('Content '+  Body.Text);
    End;
  End// retrieve_Click

Puis, IdPop3Client1 demande l'effacement du message

IdPop3.SendCmd('DELE 3');

   IdPop3Server1 déclenche OnDELE, et marque le message comme étant "à supprimer"

   IdPop3Client1 envoie QUIT et se déconnecte
   IdPop3Server1 gère OnQUIT où les messages sont effacés et libère le socket utilisé pour gérer ce client-là

   IdPop3Server1 se termine (Active devient False)


3.5 - Le résultat

Lancez le Serveur ("start"), et lorsque vous le souhaiterez, fermez le ("stop") :

tidpop3server.png



Pour le Client, cliquez "connect", "list", sélectionnez l'un des messages, cliquez "retrieve", "delete" et "disconnect"

tidpop3_client.png



Notez que

  • les sources que vous pouvez télécharger contiennent d'autres événements que nous n'avons pas détaillés ici
  • notre Client se connecte en utilisant 127.0.0.1. Toutefois, sur XP Pro, il vaut mieux utiliser l'IP du Serveur (par exemple 192.168.0.1)



4 - Améliorations

4.1 - L'exemple de Client et Serveur

Au niveau du fonctionnement de notre exemple
  • nous aurions pu implémenter des dialogues plus complexes (lecture de HEAD ou TOP, possibilité d'annuler les effacements par RESET etc)
  • côté Serveur, nous avons omis
    • la gestion des message. Celle-ci doit naturellement synchronisée avec la gestion mise en place par le Serveur SMPT
    • la gestion des exceptions et fermeture des Clients
  • côté Client, manquent, entre autres,
    • la gestion utilisateur du lecteur: (possibilité de lire depuis plusieurs boîtes aux lettres, ...)
    • la présentation de la liste des messages
    • la gestion des pièces jointes
    • le filtrage des spams
    • l'archivage des mails reçus ou rejetés
    • la possibilité de répondre (ajout d'un Client SMTP)
  • nous n'avons pas du tout géré les exceptions, ni la clôture intempestive côté Client ou Serveur


4.2 - Perspectives Indy

Notez que:
  • Indy 8 ne comporte pas de serveur POP3. Téléchargez la version 9 ou 10 de Indy
  • comme indiqué au début de l'article, nous avons ici utilisé la version Indy 9
  • le fait qu'il faille utiliser tIdPop3.Retrieve, tIdPop3.Capture, tIdPOP3ServerThread.State n'est pas d'une évidence aveuglante. Indy effectue énormément de travail d'analyse et de traitement pour nous, mais les propriétés et procédure à utiliser ne sont pas toujours bien documentés
  • le Serveur utilise tIdSync pour permettre l'affichage dans la VCL. Ces techniques sont IMPERATIVES pour éviter les problèmes de threads. Sans ce type de précautions, nous encourrons des bugs des plus sournois: exceptions, fermeture, ou pire, non fonctionnement sans aucun diagnostic. Ceci souligne bien que sans une bonne connaissance des threads, l'utilisation de Indy est assez délicate
  • le Client comporte le traditionnel tIdAntiFreeze, qui évite le gel du client en cas de lecture bloquante depuis le Client. Ici aussi, la connaissance du fonctionnement en mode sockets bloquant est utile


4.3 - Formations Tcp Ip

Pour les personnes qui souhaiteraient approfondir les communications Tcp/Ip, et surtout maîtriser les détails techniques de la librairie Indy, en particulier pour construire des protocoles sur mesure, nous organisons régulièrement des Formation Tcp/Ip sockets Delphi de deux jours.



4.4 - Diagrammes de Classe UML

Les diagrammes de classe UML permette de mieux comprendre l'articulation entre les différents composants Indy. Indy est une librairie à granularité fine. Pour comprendre quelle propriété de quel composant utiliser, il faut de toutes les façons vous construire une image mentale des relations entre ces composants. Et là, miracle, les diagrammes de classe UML vous présente en quelques figures tout ce qu'il y a savoir. Outre les articles comme celui-ci, pour nos formations, pour nos propres explorations de librairies, nous employons énormément UML. Pour ces librairies complexes, hors UML, pas de salut !




5 - Télécharger le code source Delphi

Vous pouvez télécharger: Ce .ZIP qui comprend:
  • le .DPR, la forme principale, les formes annexes eventuelles
  • les fichiers de paramètres (le schéma et le batch de création)
  • dans chaque .ZIP, toutes les librairies nécessaires à chaque projet (chaque .ZIP est autonome)
Ces .ZIP, pour les projets en Delphi 6, contiennent des chemins RELATIFS. Par conséquent:
  • créez un répertoire n'importe où sur votre machine
  • placez le .ZIP dans ce répertoire
  • dézippez et les sous-répertoires nécessaires seront créés
  • compilez et exécutez
Ces .ZIP ne modifient pas votre PC (pas de changement de la Base de Registre, de DLL ou autre). Pour supprimer le projet, effacez le répertoire.

La notation utilisée est la notation alsacienne qui consiste à préfixer les identificateurs par la zone de compilation: K_onstant, T_ype, G_lobal, L_ocal, P_arametre, F_unction, C_lasse. Elle est présentée plus en détail dans l'article La Notation Alsacienne



Comme d'habitude:

  • nous vous remercions de nous signaler toute erreur, inexactitude ou problème de téléchargement en envoyant un e-mail à jcolibri@jcolibri.com. Les corrections qui en résulteront pourront aider les prochains lecteurs
  • tous vos commentaires, remarques, questions, critiques, suggestion d'article, ou mentions d'autres sources sur le même sujet seront de même les bienvenus à jcolibri@jcolibri.com.
  • plus simplement, vous pouvez taper (anonymement ou en fournissant votre e-mail pour une réponse) vos commentaires ci-dessus et nous les envoyer en cliquant "envoyer" :
    Nom :
    E-mail :
    Commentaires * :
     

  • et si vous avez apprécié cet article, faites connaître notre site, ajoutez un lien dans vos listes de liens ou citez-nous dans vos blogs ou réponses sur les messageries. C'est très simple: plus nous aurons de visiteurs et de références Google, plus nous écrirons d'articles.



6 - Références

  • RFC 1939 : la spécification POP3 - J. Myers - M. Rose - Request for Comments: 1939 - May 1996 - Post Office Protocol - Version 3

    Mentionnons que l'aide Indy référence toutes les RFC (sous forme de liens HTTP) pour tous les protocoles mis en place

  • Client Serveur Tcp Indy : présentation de la gestion TCP/IP Indy, avec un éclairage précis sur le mode commande, qui a été créé spécifiquement pour écrire les Serveurs et Client tels que Pop3, Smtp, Ftp, Nntp etc

  • Diagrammes de classe : présentation des diagrammes de classe UML. Description avec un exemple simple

  • Formation Tcp/Ip sockets Delphi : deux jours pour comprendre le fonctionnement des communications Tcp/Ip et maîtriser les composants Indy



7 - L'auteur

John COLIBRI est passionné par le développement Delphi et les applications de Bases de Données. Il a écrit de nombreux livres et articles, et partage son temps entre le développement de projets (nouveaux projets, maintenance, audit, migration BDE, migration Xe_n, refactoring) pour ses clients, le conseil (composants, architecture, test) et la formation. Son site contient des articles avec code source, ainsi que le programme et le calendrier des stages de formation Delphi, base de données, programmation objet, Services Web, Tcp/Ip et UML qu'il anime personellement tous les mois, à Paris, en province ou sur site client.
Créé: oct-10. Maj: aou-15  148 articles, 471 sources .ZIP, 2.021 figures
Contact : John COLIBRI - Tel: 01.42.83.69.36 / 06.87.88.23.91 - email:jcolibri@jcolibri.com
Copyright © J.Colibri   http://www.jcolibri.com - 2001 - 2015
Retour:  Home  Articles  Formations  Développement Delphi  Livres  Pascalissime  Liens  Download
l'Institut Pascal

John COLIBRI

+ Home
  + articles_avec_sources
    + bases_de_donnees
    + web_internet_sockets
      – http_client
      – moteur_de_recherche
      – javascript_debugger
      + asp_net
      – client_serveur_tcp
      – site_editor
      – pascal_to_html
      – cgi_form
      + les_logs_http_bruts
      + les_blogs
      – intraweb_tutorial
      + services_web
      – serveur_web_iis
      – client_serveur_pop3
    + prog_objet_composants
    + office_com_automation
    + colibri_utilities
    + uml_design_patterns
    + graphique
    + delphi
    + outils
    + firemonkey
    + vcl_rtl
    + colibri_helpers
    + colibri_skelettons
  + formations
  + developpement_delphi
  + présentations
  + pascalissime
  + livres
  + entre_nous
  – télécharger

contacts
plan_du_site
– chercher :

RSS feed  
Blog

Architecte Delphi Architecture, Refactoring, choix de technologies, revue de code, mise en place de test, optimisation - Tél 01.42.83.69.36
Formation Delphi complete L'outil de développpement, le langage de programmation, les composants, les bases de données et la programmation Internet - 5 jours