/ clock.py
clock.py
1 """Check emails to editor@proselint.com, lint them, and reply.""" 2 3 from apscheduler.schedulers.blocking import BlockingScheduler 4 import gmail 5 import smtplib 6 from email.mime.multipart import MIMEMultipart 7 from email.mime.text import MIMEText 8 from worker import conn 9 import requests 10 import hashlib 11 import json 12 import os 13 import logging 14 import re 15 16 logging.basicConfig() 17 scheduler = BlockingScheduler() 18 19 # Settings 20 user = "hello@lifelinter.com" 21 user_to = "editor@proselint.com" 22 name = "proselint" 23 password = os.environ['gmail_password'] 24 25 tagline = "Proselint, a linter for prose." 26 url = "http://proselint.com" 27 api_url = "http://api.proselint.com/v0/" 28 29 30 def quoted(string, every=64): 31 """Insert a quote before linebreaks.""" 32 return "> " + re.sub("\r\n(?=[^\r\n])", "\r\n> ", string) 33 34 35 @scheduler.scheduled_job('interval', minutes=0.25) 36 def check_email(): 37 """Check the mail account and lint new mail.""" 38 server = smtplib.SMTP("smtp.gmail.com", 587) 39 server.ehlo() 40 server.starttls() 41 server.ehlo() 42 server.login(user, password) 43 44 g = gmail.login(user, password) 45 46 # Check for unread messages. 47 unread = g.inbox().mail(unread=True) 48 49 # Submit a job to lint each email sent to editor@proselint.com. Record the 50 # resulting job_ids somewhere (in Redis, I suppose), keyed by a hash of the 51 # email. 52 for u in unread: 53 54 u.fetch() 55 56 signature = (u.fr.decode('utf-8') + 57 u.subject.decode('utf-8') + 58 u.body.decode('utf-8')) 59 60 hash = hashlib.sha256(signature.encode('utf-8')).hexdigest() 61 62 if user_to in u.to or user_to in u.headers.get('Cc', []): 63 64 job_id = conn.get(hash) 65 66 if not job_id: 67 # If the email hasn't been sent for processing, send it. 68 r = requests.post(api_url, data={"text": u.body}) 69 conn.set(hash, r.json()["job_id"]) 70 print("Email {} sent for processing.".format(hash)) 71 72 else: 73 # Otherwise, check whether the results are ready, and if so, 74 # reply with them. 75 r = requests.get(api_url, params={"job_id": job_id}) 76 77 if r.json()["status"] == "success": 78 79 reply = quoted(u.body) 80 errors = r.json()['data']['errors'] 81 reply += "\r\n\r\n".join([json.dumps(e) for e in errors]) 82 83 msg = MIMEMultipart() 84 msg["From"] = "{} <{}>".format(name, user) 85 msg["To"] = u.fr 86 msg["Subject"] = "Re: " + u.subject 87 88 if u.headers.get('Message-ID'): 89 msg.add_header("In-Reply-To", u.headers['Message-ID']) 90 msg.add_header("References", u.headers['Message-ID']) 91 92 body = reply + "\r\n\r\n--\r\n" + tagline + "\r\n" + url 93 msg.attach(MIMEText(body, "plain")) 94 95 text = msg.as_string() 96 server.sendmail(user, u.fr, text) 97 98 # Mark the email as read. 99 u.read() 100 u.archive() 101 102 print("Email {} has been replied to.".format(hash)) 103 104 105 scheduler.start()