Blog de développement

A l'écoute des mails (Listener)

Dernière Modification le :
2024-01-13

Un changement majeur et profond a eu lieu, et on la voit de la façon la plus flagrante au niveau de la Logistique. Certes, nos fournisseurs voulaient bien, il y a quelques années, nous informer d'un numéro de suivi sur l'interface Internet que nous leur offrons. Il y a alors alors correspondance 1 à 1 entre l'information logistique du fournisseur et le dossier du client. L'information migre et le client est informé par nous de l'expédition de la commande. Ca, c'était avant...

Aujourd'hui, le fournisseur a fourni votre adresse email au transporteur (ex: UPS) qui vous informe par mail, et, s'en tient là. De même, il voulait encore bien cliquer sur un lien pour confirmer un délai. Aujourd'hui il vous envoie un A/R, avec un PDF en PJ et c'est tout!

De même nos clients prennent le pli d'attendre que l'information apparaisse sur leur téléprompteur (aka. messagerie). Vous risquez de passer un temps fou à pallier à ce problème alors que de nouvelles solutions existent.

Mettre le Serveur à l'écoute de la boite Mail

IBM décrit un Listener qui semble écouter, trier, classer des demandes de support (avec gestion de ticket) Lire →.

On identifie plusieurs étapes: récupérer les mails, les filtrer/trier, digérer, créer une action, répondre au client. Certaines sont banales, d'autres assez spécifiques. Par exemple reconnaitre un numéro de suivi chez GLS, dépendra de la langue, pourra changer au grès des modifications chez GLS, des pays, etc. La personalisation d'un package "clé en main" ne me parait pas évidente. Les points durs sont le rapatriement de la boite mail, le détachement des pièces jointes, la 'lecture' des PDF (ex: commandes, accusés de réception de commande...), le filtrage, sa sensibilité et sa spécificité.

Télécharger sa boite POP3 (Synchronisation)

Il y a pléthore d'outils commerciaux... On peut aussi instrumentaliser Outlook, qui est lourd et fait crasher le serveur. J'évite... Un point dur est le détachement des pièces jointes, point sur lequels les solutions proposées ne sont pas toujours très claires. On veut rapatrier les mails, les sauvegarder, les 'lire', y compris les pièces jointes: c'est possible!

Les transporteurs (ex: UPS) envoient des mails sans pièce jointe. Un bon vieux (trop vieux ?) composant comme Dypso POP3, ferait l'affaire. Lire → Je mets le composant, aujourd'hui disparu, dans le ZIP de ressources. Télécharger →. On trouve encore le manuel. Ca marche pour la logistique, mais on ne peut pas extraire les pièces jointes, ni lire plus de 20 mails présents sur le serveur: il faut consulter souvent.

Fetch ou getmail6 sont uniquement pour Linux. Un vieux getmail par Tim Charron a les fonctions qui m'interressent Lire et Télécharger → . Il peut extraire automatiquement les fichiers binaires codés MIME ou UU lors du téléchargement. Ne fonctionne qu'avec POP3. On peut contourner le problème en renvoyant automatiquement sur une boite mail aveugle, en POP3.

En mode Desktop, l'utilisation de Thunderbird pour la synchronisation et de l'extension FiltaQilla pour le filtrage et/ou extraction des pièces jointes est une alternative viable, économe en temps de programmation initial. Les fonctionnalités du filtrage sont larges mais parfois un peu limite

Mon Listener fait appel à de nombreuses techniques: CURL, MUNPACK, UUDECODE, PDFTOTXT, TESSERACT, etc.. Je pense même à intégrer Chat GPT et DEEP-L. Commencons par relever la boite aux lettres...

CURL, encore et toujours

C'est un outil versatile! Gratuit, robuste, intégré à Windows, populaire dans le monde Linux: il fait aussi POP3 , IMAP et ...Gmail (? à vérifier...). Lire le Manuel →. La commande intégrée de Windows a quelques rares limitations, donc, si c'est possible, on installera la dernière version. Télécharger →

On initialise nos valeurs... A noter que Curl ne crée pas les fichiers de sortie en tant que de besoin, il faut les avoir créé d'entrée de jeu.

					    Set objFSO = CreateObject("Scripting.FileSystemObject")
						
sDossierComptesFolderPath = "C:\Users\MonServeur\Documents\POP3\Comptes\"   '// à personnaliser
sMessagesPresentsFileName = "Messages_presents_sur_le_serveur_distant.txt"
sAlreadyDownloadedFileName = "Already_Downloaded.txt"
sATelechargerFileName = "A_Telecharger.txt"						
	' // On définit les comptes à surveiller.
Dim ArComptes (10, 4)
ArComptes (0,0) = "granuloshop"		'Nom de dossier
ArComptes (0,1) = "pop3.free.fr"	'serveur
ArComptes (0,2) = "granuloshop"		'utilisateur
ArComptes (0,3) = "xxxxxxx"		'mot de passe

ArComptes (1,0) = "manager"	
ArComptes (1,1) = "mail.granuloshop.com"
ArComptes (1,2) = "manager@granuloshop.com"	
ArComptes (1,3) = "xxxxxxx"		
	' // etc.
For i = 0 to 9
	If ArComptes (i,0) <> "" then 
		If NOT objFSO.FolderExists(sDossierComptesFolderPath & ArComptes (i,0) & "\") then objFSO.CreateFolder sDossierComptesFolderPath & ArComptes (i,0) & "\"
		If NOT objFSO.FolderExists(sDossierComptesFolderPath & ArComptes (i,0) & "\") then objFSO.CreateFolder sDossierComptesFolderPath & ArComptes (i,0) & ""\Inbox\"
		If NOT objFSO.FolderExists(sDossierComptesFolderPath & ArComptes (i,0) & "\") then objFSO.CreateFolder sDossierComptesFolderPath & ArComptes (i,0) & "\Mails\"
		' // CURL ne créera pas les fichiers de sortie: il faut s'assurer qu'ils existent avant tout
		' // CURL va redocumenter le fichier de messages présents sur le serveur distant				
		If NOT objFSO.FileExists(sDossierComptesFolderPath & ArComptes (i,0) & "\" & sMessagesPresentsFileName) then objFSO.CreateTextFile sDossierComptesFolderPath & ArComptes (i,0) & "\" & sMessagesPresentsFileName			
		' // Eventuellement, si on souhaite un log pour debugger ...
		' // If NOT objFSO.FileExists(sDossierComptesFolderPath & ArComptes (i,0) & "\curl_log.txt") then objFSO.CreateTextFile sDossierComptesFolderPath & ArComptes (i,0) & "\curl_log.txt"
	End If
Next
				    

Une fois au plus, on pourra vouloir consulter les services proposés par le serveur distant, en particulier la capacité à enrichir la liste des messages présents d'un identifiant unique: le nom est UIDL. Voici la commande: curl.exe -l -v -u username:password pop3://pop.free.fr

On va conserver l'historique afin de réduire les requêtes au serveur distant:

					    	' // on reconstitue l'historique, si besoin. Si le téléchargement précédent a planté, on ne repart pas de Zéro
For i = 0 to 9
	If ArComptes (i,0) <> "" then
		sHistorique = ""
		sFilePath = sDossierComptesFolderPath & ArComptes (i,0) & "\Already_Downloaded.txt"
		Set objOpen = objFSO.OpenTextFile(sFilePath, 1, true)  ' // 1 = ForReading, true créera le fichier si besoin
		If NOT objOpen.AtEndOfStream then sHistorique = objOpen.ReadAll
		objOpen.Close
		Set objOpen = nothing
		Set Folder = objFSO.GetFolder (sDossierComptesFolderPath & ArComptes (i,0) & "\InBox\")
		for each File in Folder.Files
			If NOT InStr(sHistorique, Replace (File.Name, ".eml", "")) AND File.Size > 0 then sHistorique = Replace (File.Name, ".eml", "") & VbCrLf & sHistorique
		Next
		Set objFile = objFSO.OpenTextFile(sDossierComptesFolderPath & ArComptes (i,0) & "\Already_Downloaded.txt", 2, true)    ' // 2 = ForWriting, true créera le fichier si besoin
		objFile.Write sHistorique
		objFile.Close
		Set objFile = nothing
	End If	
Next
				    

Curl va interroger le serveur distant, qui va donner une liste de message présents avec un identifiant unique.

					    sBat = ""
For i = 0 to 9
	If ArComptes (i,0) <> "" then
		sBat = sBat & VbCrLf & """curl.exe"" -X ""UIDL"" -v -o """ & sDossierComptesFolderPath & ArComptes (i,0) & "\" & sMessagesPresentsFileName & """ -u " & ArComptes (i,2) & ":" & ArComptes (i,3) & "  pop3://" & ArComptes (i,1)
	End If
Next
sCurlBatListFilePath = "C:\Users\MonServeur\Documents\POP3\Curl_Bat.bat"   ' // a personaliser
Set objFile = objFSO.OpenTextFile(sCurlBatListFilePath, 2,true)   ' // 2= ForWriting
objFile.Write sBat
objFile.Close
Set objFile = nothing

Command = """" & sCurlBatListFilePath & """" 
oShell.Run Command, 0, True
				    

On dispose maintenant de la liste des messages, chacun avec un identifiant unique. On construit une liste de messages à télécharger, en excluant ceux qui ont déjà été téléchargés.

"curl.exe -o """ & sDossierComptesFolderPath & ArComptes (i,0) & "\InBox\" & sUID & ".eml"" -u " & ArComptes (i,2) & ":" & ArComptes (i,3) & " pop3://" & ArComptes (i,1) & "/" & sNumero

Dans la commande CURL:
-o désigne le dossier et le nom attribué au mail. On veille à ne pas avoir de caractères interdits
-u désigne l'utilisateur suivi de : et le mot de passe
- ensuite, le protocole et le serveur suivi du numéro d'ordre du message (non pas son Indentifiant Unique...) Exemple: pop3://free.fr/Numero
POP3 est un protocole assez rustique et ancien, il reste accessible avec la commande TELNET.

					    	' // on reconstitue l'historique, si besoin. Si le telechargement precedent a planté, on ne repart pas de Zéro
For i = 0 to 9
	If ArComptes (i,0) <> "" then
		sHistorique = ""
		sFilePath = sDossierComptesFolderPath & ArComptes (i,0) & "\Already_Downloaded.txt"
		Set objOpen = objFSO.OpenTextFile(sFilePath, 1,true)   ' // ForReading = 1 , true va créer le fichier si besoin
		If NOT objOpen.AtEndOfStream then sHistorique = objOpen.ReadAll
		objOpen.Close
		Set objOpen = nothing
		Set Folder =objFSO.GetFolder (sDossierComptesFolderPath & ArComptes (i,0) & "\InBox\")
		for each File in Folder.Files
			If NOT InStr(sHistorique, Replace (File.Name, ".eml", "")) AND File.Size > 0 then sHistorique = Replace (File.Name, ".eml", "") & VbCrLf & sHistorique
		Next
		Set objFile = objFSO.OpenTextFile(sDossierComptesFolderPath & ArComptes (i,0) & "\Already_Downloaded.txt", 2,true)  ' // ForWriting =2
		objFile.Write sHistorique  ' & VbCrLf
		objFile.Close
		Set objFile = nothing
		
		sA_telecharger = ""
		sFilePath = sDossierComptesFolderPath & ArComptes (i,0) & "\Messages_presents_sur_le_serveur.txt"
		Set objOpen = objFSO.OpenTextFile(sFilePath, 1,true)	' // ForReading = 1
		ObjOpen.Close
		Set objOpen = nothing
		If NOT objOpen.AtEndOfStream then
			Do While NOT objOpen.AtEndOfStream 
				sLine = trim(objOpen.ReadLine)
				If sLine <> "" then
					If InStr(sLine, " ") > 0 then
						nMessage = nMessage + 1
						sNumero = ""
						sNumero = Trim (Left(sLine, InStr(sLine, " ") -1))
						sUID = replace (sLine, sNumero, "")
						sUID = trim(replace (sUID, " ", ""))
						sUID = Normalize(sUID)
						if sNumero <> "" AND InStr(sHistorique, sUID) = 0 then 
							if sBat <> "" then sBat = sBat & VbCrLf
							StrBat = StrBat & "curl.exe  -o """ & sDossierComptesFolderPath & ArComptes (i,0) & "\InBox\" & sUID & ".eml"" -u " & ArComptes (i,2) & ":" & ArComptes (i,3) & "  pop3://" & ArComptes (i,1) & "/" & sNumero 
							if sA_telecharger <> "" then sA_telecharger = sA_telecharger & VbCrLf
							sA_telecharger = sA_telecharger & sUID
						End If
					End If
				End If
			Loop
		End If 		
	End If	
Next
				

Sauvegardons notre ligne de commande pour déverminage éventuel. Puis on y va!

					    Set objFile = objFSO.OpenTextFile(sCurlBatMessagesFilePath, 2,true)  ' // ForWriting=2
objFile.Write sBat
objFile.Close
Set objFile = nothing

Command = """" & sCurlBatMessagesFilePath & """" 
if sBat <> "" then oShell.Run Command, 0, True
				

On renomme les mails pour plus de lisibilité

Avec POP3, les mails sont identifiés par un GUID, unique certes, mais illisible: ce n'est pas pratique pour l'inévitable débogage! Donc, à coté de nos dossiers Inbox, nous créons des dossiers Mails, où le nom de fichier est lisible est permet de vérifier les fonctions de filtrage, par exemple.

On renomme à partir du domaine de l'expéditeur et du titre. Il est utile de mettre le nom de domaine de l'expéditeur en tête du nom de fichier, suivi du titre. Il faut prendre soin de corriger ce nom de fichier pour qu'il soit licite (au sens de Windows/DOS). Par ailleurs pour éviter d'avoir à vérifier pour chaque petit programme que je suis amené à utiliser, je convertis les caratères non-ANSI en ANSI, comme cela on est tranquille.

On trouve ici une liste de charactères à éviter: Lire →. Une discussion complete est disponible sur Stackoverflow Lire → et cette réference par Microsoft Lire →

image

Tout caractère dont le code UNICODE est inférieur à 128 est ASCII

Pour les charactères du deuxieme bloc de ISO/IEC 8859-1 on met une substitution, s'il y en a d'évidente. Sinon, on ne fait rien, le charactères sera éliminé plus loin... Lire Wikipedia →

Ensuite on élimine tout caractère qui n'est pas dans cette liste où l'on a pris soin de laisser l'espace blanc, qui se trouve ici entre ! et ] (et de retirer le &, la virgule et le point)
[abcdefghijklmnopqrstuvwxyzz0123456789+=_-)(*%#! ]

Les noms de fichiers sur les systèmes Windows ne peuvent pas contenir les caractères suivants : \<>:\"/|?*.

Le VBS est disponible dans le ZIP de Ressoures. Télécharger →

					    ' // Cette fonction substitue et élimine des caractères en vue de faire des noms de fichiers lisibles à partir du titre d'un email
Function StripChars(sT)
		' // https://www.experts-exchange.com/questions/24454280/Best-way-to-remove-non-ascii-characters.html
		'// LIKE ne fonctionne pas en VBS
	Dim intCount
		' // Pour les caractères du deuxieme bloc de ISO/IEC 8859-1 on met des substitutions, s'il y en a. Sinon, on ne fait rien, le caracteres sera elimine plus loin... 
		' // https://en.wikipedia.org/wiki/ISO/IEC_8859-1
		' // caractères qui n'ont pas de sustitution "¤" "§" "¦" "¨" "ª" "¬" "®" "¶"
	sT = Replace(sT, "¡","!") : sT = Replace(sT, "¢","c") : sT = Replace(sT, "£","GBP") : sT = Replace(sT, "¥","YEN") : sT = Replace(sT, "©","c") : sT = Replace(sT, "«","""")
	sT = Replace(sT, "¯","-") : sT = Replace(sT, "°","o") : sT = Replace(sT, "±","+/-") : sT = Replace(sT, "²","2") : sT = Replace(sT, "³","3") : sT = Replace(sT, "´","'")
	sT = Replace(sT, "µ","micron") : sT = Replace(sT, "·",".") : sT = Replace(sT, "¸",".") : sT = Replace(sT, "¹","1") : sT = Replace(sT, "º","o") : sT = Replace(sT, "»","""")
	sT = Replace(sT, "¼","1/4") : sT = Replace(sT, "½","1/2") : sT = Replace(sT, "¾","3/4") : sT = Replace(sT, "¿","?") : sT = Replace(sT, "À","A") : sT = Replace(sT, "Á","A")
	sT = Replace(sT, "Â","A") : sT = Replace(sT, "Ã","A") : sT = Replace(sT, "Ä","A") : sT = Replace(sT, "Å","A") : sT = Replace(sT, "Æ","AE") : sT = Replace(sT, "Ç","C")
	sT = Replace(sT, "È","E") : sT = Replace(sT, "É","E") : sT = Replace(sT, "Ê","E") : sT = Replace(sT, "Ë","E") : sT = Replace(sT, "Ì","I") : sT = Replace(sT, "Í","I")
	sT = Replace(sT, "Î","I") : sT = Replace(sT, "Ï","I") : sT = Replace(sT, "Ð","D") : sT = Replace(sT, "Ñ","N") : sT = Replace(sT, "Ò","N") : sT = Replace(sT, "Ó","O")
	sT = Replace(sT, "O","O") : sT = Replace(sT, "Õ","O") : sT = Replace(sT, "Ö","O") : sT = Replace(sT, "×","x") : sT = Replace(sT, "Ø","dia.") : sT = Replace(sT, "Ù","U")
	sT = Replace(sT, "Ú","U") : sT = Replace(sT, "Û","U") : sT = Replace(sT, "Ü","U") : sT = Replace(sT, "Ý","Y") : sT = Replace(sT, "Þ","b") : sT = Replace(sT, "ß","ss")
	sT = Replace(sT, "à","a") : sT = Replace(sT, "á","a") : sT = Replace(sT, "â","a") : sT = Replace(sT, "ã","a") : sT = Replace(sT, "ä","a") : sT = Replace(sT, "å","a")
	sT = Replace(sT, "æ","ae") : sT = Replace(sT, "ç","c") : sT = Replace(sT, "è","e") : sT = Replace(sT, "é","e") : sT = Replace(sT, "ê","e") : sT = Replace(sT, "ë","e")
	sT = Replace(sT, "ì","i") : sT = Replace(sT, "í","i") : sT = Replace(sT, "i","i") : sT = Replace(sT, "ï","i") : sT = Replace(sT, "ð","d") : sT = Replace(sT, "ñ","n")
	sT = Replace(sT, "ò","o") : sT = Replace(sT, "ó","o") : sT = Replace(sT, "ô","o") : sT = Replace(sT, "õ","o") : sT = Replace(sT, "ö","o") : sT = Replace(sT, "ö","/")
	sT = Replace(sT, "ø","dia.") : sT = Replace(sT, "ù","u") : sT = Replace(sT, "ú","u") : sT = Replace(sT, "û","u") : sT = Replace(sT, "ü","u") : sT = Replace(sT, "ý","y") : sT = Replace(sT, "þ","b") : sT = Replace(sT, "ÿ","y")

		' // https://www.mtu.edu/umc/services/websites/writing/characters-avoid/
		' // caractères qui n'ont pas de sustitution  # pound % percent & ampersand { left curly bracket } right curly bracket \ back slash < left angle bracket  > right angle bracket * asterisk  ? question mark / forward slash  blank spaces $ dollar sign  ! exclamation point 	  single quotes	 " double quotes	 : colon	 @ at sign 
		' // Là où Thunderbird a proposé une substitution, on fait de même...

	sT = replace (sT, "&", "+") : sT = replace (sT, "\", "-") : sT = replace (sT, "*", "-") : sT = replace (sT, "?", "-")
	sT = replace (sT, "/", "-") : sT = replace (sT, ":", "-") : sT = replace (sT, "@", "-")
		' // On substitue aussi la virgule et le point
	sT = replace (sT, ",", "-") : sT = replace (sT, ".", "-")
	
    For intCount = 1 To Len(sT)
	   ' // cette formule autorise le blanc mais pas &
		If InStr(1,"[abcdefghijklmnopqrstuvwxyz0123456789+=_-)(*%#! ]", Mid(sT, intCount, 1),1) > 0 Then
            StripChars = StripChars & Mid(sT, intCount, 1)
        End If
    Next	
	Do While InStr(StripChars, "__") > 0 OR InStr(StripChars, "--") > 0 OR InStr(StripChars, "  ") > 0
		StripChars = replace (StripChars, "__", "_") : StripChars = replace (StripChars, "--", "-") : StripChars = replace (StripChars, "  ", " ")
	Loop	
End Function
				

A propos de l'unicité du nom...

Le UID sur serveur POP est unique. Pas le titre du mail. Or, certains clients envoient le même mail sur plusieurs boites, le serveur mail crée aussi des doublons... Donc, dans le contexte du Listener, éliminer ces doublons est plutôt une bonne idée: un mail reçu sur la boite A sera traité et marqué comme tel. Le même mail reçu sur la boite B, ne sera pas traité, puisqu'il est marqué comme traité.

A l'inverse les systèmes automatiques tels que UPS et en particulier GLS, envoient des mails différents avec le même titre (et pas de pièce jointe). A ces mails, comme à ceux dont le titre est un peu court, on ajoute un GUID

If  InStr(1, sentete, "GLS", 1) > 0 OR InStr(1, sentete, "UPS", 1) > 0 OR Len(sSujet) < 25 then		'InStr(1, sentete, "UPS", 1) > 0 OR  ' Pour l'instant je n'aile pb qu'avec GLS
	'il faut recréer une instance puis la purger à chaque fois, sinon, il donne le même résultat!
	Set TypeLib = CreateObject("Scriptlet.TypeLib")
	myGuid = TypeLib.Guid
	myGuid = Replace(myGuid, "{","")
	myGuid = Replace(myGuid, "}","")
	myGuid = Replace(myGuid, "-","")
		' // Quand on veut le GUID complet, ce qui n'est pas le cas ici...  myGuid = Replace(Left(myGuid, Len(myGuid)-2),"-","")
	sTitre = sTitre & "_" & Left(myGuid,6)
	set TypeLib = nothing
End If

Un peu de nettoyage...

Il y a 3 nettoyages à effectuer: les dossiers locaux, les listes d'historique (ou base de données, le cas échéant), les dossiers POP3 distants. On ne fait le nettoyage qu'une seule fois par jour, aux heures creuses (ex. 6 heures du matin).

					    	' //  Lecture de la date de nettoyage quotidien dans le fichier correspondant. Les dates sont au format ISO simplifié, c-à-d. sans tiret
sDate_Nettoyage_Quotidien = "20220101" ' // valeur par défaut
sDateNettoyageQuotidienFileName = "Nettoyage_Quotidien.txt"
sDateNettoyageQuotidienFilePath = "C:\Users\MonCompte\MyDocuments\Listener\" ' // A personnaliser
sAujourdhui = ToIsoDateSimplified (Now())
Set objOpen = objFSO.OpenTextFile(sDateNettoyageQuotidienFilePath, 1, true)  ' // 1 = ForReading, true créera le fichier si besoin
If NOT objOpen.AtEndOfStream then sDate_Nettoyage_Quotidien = trim(objOpen.ReadLine)
objOpen.Close
Set objOpen = nothing

' Vérification si le nettoyage quotidien doit être effectué aujourd'hui
Do_Nettoyage_Quotidien = False
If sAujourdhui > sDate_Nettoyage_Quotidien AND Hour(Now()) > 5 then	Do_Nettoyage_Quotidien = True

Private Function StrN2(n)
	If Len(CStr(n)) < 2 Then StrN2 = "0" & n Else StrN2 = n
End Function
Public Function ToIsoDateSimplified (datetime)
	ToIsoDateSimplified = CStr(Year(datetime)) & StrN2(Month(datetime)) & StrN2(Day(datetime))
End Function 

				

On crée une table des dossiers à purger de sorte à éviter l'inflation et on définit une durée limite (ex: 15 j.) en incluant les dossiers de reception sur chaque boite mise sous surveillance.

De même, on crée une liste des fichiers cumulatifs, historiques, avec éventuellemet un cap et un cap par défaut. Avant chaque action, le fichier cumulatif est pris en considération pour éviter de refaire ce qui a déjà été fait.

					    DIM ArDossiers_A_Nettoyer (50)
ArDossiers_A_Nettoyer (0) = sLogFolderPath	' // A personaliser et compléter
j=49
For i = 0 to 9
	If ArComptes (i,0) <> "" then 
		ArDossiers_A_Nettoyer (j) = sDossierComptesFolderPath & ArComptes (i,0) & "\Inbox\"
		ArDossiers_A_Nettoyer (j-1) = sDossierComptesFolderPath & ArComptes (i,0) & "\Mails\"
		j=j-2
	End If
Next
DIM  ArFichiersHistoriques (20,2)
ArFichiersHistoriques (1,0) = sAlreadyDownloadedFilePath	' // A personaliser et compléter
ArFichiersHistoriques (1,1) = 3000	' // ici, pas plus de 3000 lignes dans ce fichier

				
					    if Do_Nettoyage_Quotidien then 
	' // Call Log ( VbCrLf & "*****" & VCrLf & "On entre dans le module de Nettoyage *****")
	' // Call Log ("On fait un petit nettoyage journalier, car sAujourdhui: " &  sAujourdhui & "   sDate_Nettoyage: " & sDate_Nettoyage & " et Do_Nettoyage_Quotidien : " & Do_Nettoyage_Quotidien)
		For i = 0 to 50
			If ArDossiers_A_Nettoyer (i) <> "" then 
				If objFSO.FolderExists(ArDossiers_A_Nettoyer (i)) then				
					Set Folder =objFSO.GetFolder (ArDossiers_A_Nettoyer (i))
					For each File in Folder.Files
						sFileName = File.Name
						dtLastModified = CDate(Int(File.DateLastModified))
						delta = sDayStamp - dtLastModified	
						if Delta > DeltaMax AND objFSO.FileExists(ArDossiers_A_Nettoyer (i) & sFileName ) then objFSO.DeleteFile ArDossiers_A_Nettoyer (i) & sFileName 				
					Next
				End If
			End If
		Next		
			' // les fichiers cumulatifs sont tronqués de facon à ne pas devenir trop long
		For i = 0 to 20
			If ArFichiersHistoriques (i,0) <> "" then 
				j=0
				JMax = 1000
				if ArFichiersHistoriques (i,1) <> "" then JMax = CInt(ArFichiersHistoriques (i,1))
				sNew = ""
				Set objOpen = objFSO.OpenTextFile(ArFichiersHistoriques (i,0), ForReading,true)
				If NOT objOpen.AtEndOfStream then 
					Do While NOT objOpen.AtEndOfStream						
						sLine = objOpen.ReadLine
						if j <  JMax AND trim(sLine) <> ""  then sNew = sNew & VbCrLf & trim(sLine) : j=j+1
					Loop
				End If
				objOpen.Close
				Set objOpen = nothing
				If sNew <> "" then 
					Set objOpen = objFSO.OpenTextFile(ArFichiersHistoriques (i,0), ForWriting,true)
					objOpen.Write sNew
					objOpen.Close
					Set objOpen = nothing
				End If
			End If
		Next
			' // En fin de nettoyage, on metà jour la date du dernier nettoyage fait
		Set objFile = objFSO.OpenTextFile(sDateNettoyageQuotidienFilePath, ForWriting,true)
		objFile.Write sAujourdhui
		objFile.Close
		Set objFile = nothing		
	Else
		' // Call Log ("On ne fait pas de petit nettoyage")
End If
				

Les boites mails étant, par ailleurs, surveillées par Thunderbird, on lui laisse la tache de nettoyer régulièrement le serveur POP3.

Et ensuite ? Le WorkFlow post-synchro

Le WorkFlow est le suivant:
  1. La Synchronisation avec le serveur de Mail (ce billet ici même)
  2. Tri et distribution du courrier Lire →
  3. L'Extraction et transformation des pièces jointes
  4. La Lecture OCR
  5. L'extraction de données
  6. La definition des taches
  7. La Validation manuelle éventuelle
  8. L'execution
https://forums.ivanti.com/s/article/Creating-a-workflow-to-send-an-email-when-a-listener-stops-working?language=en_US