URL: https://linuxfr.org/users/rakoo/journaux/etre-averti-de-ses-emails-intelligemment Title: Être averti de ses emails intelligemment Authors: rakoo Date: 2013年04月03日T00:49:02+02:00 Tags: ruby et imap Score: 14 Ah ! 'Nal ! _Je préfère t'avertir dès maintenant : tu es un journal, je te raconte ma vie._ Combien de fois n'ai-je pas lu ce genre de théorie : _GMail c'est pas bien, il faut s'auto-héberger!_. Au fil de mes expériences dans le libre, j'ai moi aussi peu à peu succombé à cette théorie, et ai même installé mon propre [MTA](http://fr.wikipedia.org/wiki/Mail_Transfer_Agent), [OpenSMTPd](http://www.opensmtpd.org/), pour essayer de m'émanciper de cette grande prison si dorée (et puis aussi, je dois l'avouer, parce que je suis curieux). Malheureusement, c'est pas aussi simple que ça. Comme tu le sais, s'auto-héberger ne se fait pas d'un claquement de doigt; tu pourras demander au justicier Zenitram, toujours prêt à aller contre le courant avec ses satanés arguments, ou même à n'importe qui ayant réellement tenté l'aventure. Impossible de tanner mes contacts et de leur dire _Je ne suis plus disponible à cette adresse, veuillez me contacter à celle-ci_ avant d'avoir quelque chose d'un peu stable. Bon, très bien, je m'en vais jouer avec les paramètres de GMail et lui dire de _forwarder_ chaque mail sur mon domaine, pour pouvoir jouir de mes emails chez moi... Horreur ! J'ai l'outrecuidance d'avoir un nom de domaine et un nom d'utilisateur trop longs, et [ça ne respecte pas la RFC!](https://productforums.google.com/forum/#!msg/gmail/c4p7De0I2SA/noU84GPw80sJ) Bon, en attendant que GMail règle le problème de son côté (hahaha), il va me falloir une autre solution. J'avais configuré, depuis quelque temps déjà, [OfflineIMAP](http://offlineimap.org/) pour synchroniser mes emails. Ça marche, tout va bien... sauf qu'il faut lancer à la main. C'est quand même un peu stupide de lancer le bidule à la main à chaque fois et d'attendre qu'il ait fini avant de m'apercevoir que non, je n'ai pas d'amis. Pour la petite note, OfflineIMAP a été fait pour assurer l'intégrité des messages avant tout, au détriment des performances. Un choix qu'on ne peut certainement pas reprocher a ses créateurs, mais ça veut tout de même dire 30 secondes à attendre à chaque fois... `cron`, tu me dis ? Oh, mais ça voudrait dire demander toutes les `X` minutes si quelque chose de nouveau s'est passé. Les serveurs de GMail ont beau être taillés pour, s'il y a une chose que je déteste, c'est le _polling_. Il va me falloir autre chose. Je fouille dans ma mémoire et je me souviens, après mes quelques pérégrinations avec [IMAP](http://tools.ietf.org/html/rfc3501), que celui-ci avait une commande `IDLE` qui disait au serveur "dès que tu as quelque chose de neuf, fais moi signe !". Parfait ! Exactement ce qu'il me faut ! Bon, c'est pas dans cette RFC, c'est dans [l'autre](http://tools.ietf.org/html/rfc2177), mais GMail la supporte. Après quelques recherches chez Google (décidément, celui-ci est partout), je suis surpris qu'il n'y ait pas de solution simplissime pour être averti d'un email. Oh, il y a bien quelques petits machins qui avertissent l'utilisateur de nouveaux messages, mais j'ai peur qu'ils ne fassent rien d'autre que du _polling_ à intervalle prédéfini. Et puis, bon, un simple `IDLE`, ça doit pas être compliqué à mettre en place quand même ? Et bien voilà, un script `ruby` fait à la main, qui me donne tout ce dont j'ai envie : ```ruby require 'net/imap' require 'trollop' opts = Trollop::options do opt :login, "Login", :type => :string opt :pass, "Pass", :type => :string opt :mailbox, "The mailbox to watch", :default => "[Gmail]/All Mail" end raise "No login !" unless opts[:login] raise "No password !" unless opts[:pass] def debug str puts "[#{Time.now.to_s}] #{str}" end # Start of execution imap = Net::IMAP.new 'imap.gmail.com', ssl: true imap.login opts[:login], opts[:pass] imap.select opts[:mailbox] Thread.new do debug "Starting timer" loop do sleep 29 * 60 imap.idle_done end end # A nice message for user debug "Starting idle loop over here" loop do begin imap.idle do |resp| if resp.kind_of?(Net::IMAP::ContinuationRequest) and resp.data.text == 'idling' # Server has received the IDLE order and will start emmitting stuff when a new mail arrives debug "Starting idle loop over there" end if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == 'EXISTS' # New mail ! We don't read what the server sent us, we just use the fact that there is something new debug "Running sync" system('offlineimap -u Quiet') debug "Ran sync" end end rescue Errno::ECONNRESET debug "Connection reset by peer" retry end end ``` Quelques explications, en vrac : • tu vas avoir besoin de la _gem_ `trollop`. Si tu ne l'as pas déjà, tu verras à quel point il est plaisant de travailler avec. • je considère que tu as correctement configuré `offlineimap` pour qu'il se lance tel quel. Il faudra donc mettre le mot de passe en clair dans un fichier... • Il sert à quoi ce Thread en plus ? La RFC sur `IDLE` dit qu'un serveur peut considérer un client ayant passé un `IDLE` comme étant inactif au bout de 30 minutes sans activité, et le déconnecter. Cette même RFC conseille donc que le client déconnecte l'`IDLE` (en l'annoncant au serveur) et en relance un. Un _keepalive_ propre, en somme. Du coup, lorsque le Thread lancera `imap.idle_done`, le bloc `imap.idle` va se finir, et la boucle va relancer un `imap.idle`. On est reparti pour un tour. En tout cas, pas de souci côté `ruby`, l'objet `Net::IMAP` est _thread-safe_. Tu l'auras deviné, ce n'est pas du très haut-niveau, mais ça marche pour ce que je lui demande de faire. Le but était d'avoir le moins de dépendances possibles (bon, il y a quand même `trollop`, mais cette _gem_ vaut de toute façon le coup d'être installée). À part ça, c'est du ruby standard, testé sur `MRI 1.9.3` Comment ça se lance ? Après avoir installé un interpréteur `ruby` et la _gem_ `trollop`, tout se fait dans le terminal. Personnellement, je l'utilise comme ça : ``` $ ruby idlewatch.rb --login "login" --pass "mot de passe" || notify-send -u critical idlewatch "just crashed :(" ``` ça me permet d'être averti quand un problème se passe, grâce à `notify-send`. Dès qu'il y a un problème, je peux aller voir le terminal et lire ce qu'il s'est passé. Note qu'il y a un autre argument, `mailbox`, que je n'utilise pas, et qui te permet de choisir la boîte à surveiller. Chez GMail, celle qui stocke tout les emails est `[Gmail]/All Mail`; un choix judicieux. Je lance le tout dans un [tmux](http://tmux.sourceforge.net/) pour faire tourner en arrière-plan, mais [screen](http://www.gnu.org/software/screen/) ferait parfaitement l'affaire. Le minimaliste [dtach](http://dtach.sourceforge.net/) a même été conçu pour ce cas d'utilisation. Je te livre ça, 'Nal, en espérant que ça puisse te servir d'une quelconque façon. Retiens tout de même que mon souhait de base était d'avoir un script le plus simple possible. Pas de paquets, pas d'installateur, juste un script que je peux coller dans mon éditeur de texte préféré et bidouiller comme bon me semble. J'espère également que la soupe de formatage _markdown_ n'aura pas été indigeste. **Note**: si question se pose, tout ce que vous voyez dans ce présent journal est placé sous licence [CC0](http://creativecommons.org/publicdomain/zero/1.0/).

AltStyle によって変換されたページ (->オリジナル) /