Introduction au protocole NNTP
Regroupés au sein de Usenet, les groupes de discussion gérés par le protocole NNTP ("Networks News Transfer Protocol") ont encore de beaux jours devant eux malgré l'avancée des forums (PhpBB et consorts) sur les pages web. On peut s'y abonner, les consulter en tout temps et poster des messages. Nous allons utiliser Python pour réaliser un petit lecteur de nouvelles qui permettra de rapatrier les messages d'un groupe. 
Introduction.
À la fin des années 70, les protocoles pour utiliser les réseaux se multiplient. En 1972, le courriel apparaît, suivi de TCP/IP une année plus tard. Si le courriel est intéressant pour quelques échanges, la solution apparaît moins commode pour établir des discussions entre plusieurs utilisateurs. Le concept de « mailing-list » est alors inventé pour permettre des envois à plusieurs correspondants abonnés. En 1979, des étudiants de la Duke University en Caroline du Nord, Tom Truscott et Jim Ellis planchent sur une innovation en la matière : réaliser un réseau qui se chargerait de stocker les messages qui pourraient être consultés à tout moment. C'est ainsi que débute l'histoire d'Usenet, contraction de « Unix User Network ». Aidés par d'autres étudiants, ils réalisent un réseau entre leur université et la University of North Carolina. 
Un protocole est spécialement développé pour gérer la diffusion des nouvelles : UUCP. Le réseau de nouvelles se répand rapidement au travers d'ARPANET et d'autres types de connexions (BBS, Fidonet, X.25, etc.). En 1984, le nombre de serveurs UUCP se monte à plus de 900 mais devant un tel succès, des modifications doivent être envisagées. Une des plus importantes est le passage à TCP/IP qui le lie à Internet. De plus, UUCP constitue un gouffre à ressources : chaque serveur transmet un nouveau message à un autre serveur sans vérifier si ce dernier le possède déjà. Les serveurs croulent ainsi sous des messages inutiles qui saturent le réseau. Avec l'expansion de Usenet, la masse de messages devient rapidement ingérable. 
Le protocole UUCP est alors abandonné au profit de NNTP (Networks News Transfer Protocol), présenté en février 1986 par Brian Kantor et Phil Lapsley dans la RFC-977 (puis mis à jour par C.Feather dans la RFC-3977 en Octobre 2006). NNTP résout ce problème en introduisant la notion d'interaction entre les serveurs. Un serveur peut demander la liste de groupes et d'articles d'un autre serveur et rapatrier les messages désirés. Le réseau peut aussi être fragmenté entre gros et petits serveurs, ces derniers s'occupant par exemple d'une liste plus restreinte de groupes ou faisant office de cache. 
Plusieurs universités dont Berkeley travaillent sur les applications côté serveur en essayant d'optimiser la gestion des messages et le système est remodelé pour obtenir la structure que nous connaissons aujourd'hui. Usenet devient une vitrine de prédilection, des annonces importantes y sont faites et des groupes concernant les sujets les plus divers allant de l'anodin au sulfureux (alt.sex, groupes de secte, etc.) se répandent. Le 6 août 1991, Tim Berners-Lee annonce dans alt.hypertext la création du « WorldWideWeb project ». Dans l'ordre des choses, le spam y fait son apparition dès 1994. On attribue la paternité du spam sur Usenet à Clarence Thomas avec le message « Global Alert For All : Jesus is Coming Soon » (17 janvier 1994). Il sera suivi peu après par un spam sur le génocide arménien puis le premier véritable spam commercial sur Usenet orchestré par deux avocats américains.
schéma de fonctionnement général :
Aperçu du protocole NNTP.
Le protocole NNTP est basé sur une suite de commandes et de réponses en ASCII comme SMTP. Les communications se font en général via le port 119 du serveur. Les réponses retournées par un serveur sont divisées en deux catégories dans la RFC : réponses « textuelles » et réponses « états » sous la forme de nombres. Les indications d'états permettent de savoir si une commande envoyée par le client a été correctement traitée par le serveur. Des paramètres peuvent être joints à l'identifiant de l'état du serveur. Une certaine liberté est prévue au travers de messages de débogage. Une commande réussie retournera un code de type 2xx (par exemple, 211 pour la commande GROUP). Les codes 4xx et 5xx sont des messages d'erreurs.
Instructions complémentaires au standard RFC-977 (notamment amenées par la RFC-3977) : 
Grâce à un client Telnet, il est possible d'expérimenter ces commandes. Voici un exemple de session sur un serveur en lecture seule mais à l'accès libre : 
En plus de ces commandes conformes à la RFC-977, quelques commandes ont été ajoutés au fil du temps pour combler quelques lacunes du protocole initial : 
Exemple simple de Dialogue NNTP pour le post d'un article par un client:
 [C] POST (1)
 [S] 340 Input article; end with <CR-LF>.<CR-LF> (2)
 [C] From: "Macstras" mactras@ulp.u-strasbg.fr (3)
 [C] Newsgroups: misc.test (3)
 [C] Subject: Demo pour l’expose MGP2i (3)
 [C] Organization: Personnel (3)
 [C] (3)
 [C] Article de demonstration. (3)
 [C] . (3)
 [S] 240 Article received OK (4)
[C] : Client
[S] : Serveur
(1) Le client envoi la commande Post pour notifier le serveur d’un envoi d’article.
(2) Le serveur répond au client qu’il est prêt à recevoir les éléments de l’article à poster et spécifie au client la commande de fin du message.
(3) Le client constitue le message en envoyant unitairement chaque champ (obligatoire ou optionnel) constitutif de l’article.
(4) Le serveur envoi le message d’état confirmant le succès de la prise en compte de l’article
Le format des messages sur USENET.
Décrit au départ dans la RFC 850, le format des messages fut mis à jour dans la RFC 1036. Plusieurs formats se sont cotoyés mais à notre connaissance, tous les messages sont désormais formatés selon les principes utilisés pour le courriel. 
Un message comporte donc les inévitables champs “From”, “Subject”, etc. Les en-têtes peuvent être examinées grâce à la plupart des clients comme Thunderbird ou encore via Telnet au travers de la commande HEAD (voir l'exemple de session). Dans Thunderbird, en affichant l'intégralité du message, on peut voir les différents champs présents dans un message. On y retrouve des infos diverses comme le client utilisé pour l'envoi, la date d'envoi, le nom et le type du serveur, etc. 
Les plus intéressants du point de vue du NNTP sont le champ « Message-ID », les champs « Path » et surtout « References ». L'identifiant est sous la forme d'une adresse mail, il est unique avec un contenu aléatoire. La spécification recommande de ne pas utiliser le même identifiant avant deux ans, on peut toutefois se demander si ce conseil est encore valable. Le champ « Path » résume le chemin emprunté par le message pour arriver depuis l'expéditeur jusque dans votre serveur de nouvelles. En général, il y a relativement peu d'intermédiaires. 
Le champ « References » résume toute l'historique d'un message et permet de déterminer sa position dans l'arborescence d'un « thread » (discussion). La figure 1 montre comment le champ « References » évolue selon la hiérarchie du message : de droite à gauche dans le champ, on trouve l'identifiant du message parent, suivi du message grand-parent et ainsi de suite jusqu'à arriver au premier message de la discussion concernée. Il est ainsi possible d'afficher les messages dans une structure en arbre comme dans Thunderbird en analysant les identifiants et en demandant au serveur d'envoyer les messages correspondants. À noter que le premier message d'une discussion n'a pas de champ « References » car il n'a bien entendu pas de parent. 
Mise en œuvre avec Python.
Python propose une librairie nommée "nntplib" qui gère les commandes NNTP. Réaliser une lecture automatique des messages d'un groupe donné est ainsi très facile, les noms des méthodes de la classe NNTP correspondent aux commandes en ASCII du protocole NNTP. 
Après avoir importé nntplib, on construit une instance via nntplib.NNTP(nom_du_serveur), la connexion est automatiquement lancée. On ne manquera pas d'englober les différents appels de fonctions dans des blocs try/except pour prendre en charge les erreurs et autres exceptions. La méthode « group » permet d'indiquer le groupe désiré. En retour, on obtient un tuple avec les informations sur le groupe : nombre d'articles, premier article, dernier article. 
On peut ensuite lancer une récupération du message en indiquant à la méthode « article » le numéro de l'article désiré. De la même manière que dans le protocole NNTP, l'en-tête peut être récupérée grâce à la méthode « head » et le contenu via « body ». Les tuples obtenus contiennent les champs du message. Le listing proposé récupère les 10 derniers messages dans le groupe « sci.crypt » et affiche leur contenu. Constituer une arborescence est un peu plus compliqué, il faut analyser le champ « References » et faire des appels à « article » avec les identifiants désirés, nous avons volontairement laissé de côté cette fonctionnalité. 
Pour poster des messages, la démarche est un peu plus complexe car il faut respecter les champs indiqués dans la spécification (RFC 1036), la méthode « post » de la classe NNTP permet ensuite d'envoyer le message. À cet effet, plusieurs groupes de test existent si vous voulez essayer de programmer une fonction d'envoi (alt.test, de.test, it.test, etc.). Pour l'envoi, le mieux est de se connecter au serveur de nouvelles de son fournisseur d'accès plutôt qu'un serveur gratuit, le constructeur de la classe NNTP permet d'indiquer le mot de passe et le nom d'utilisateur.