diff options
| -rw-r--r-- | email_helpers.py | 141 | ||||
| -rw-r--r-- | famille.py | 24 |
2 files changed, 153 insertions, 12 deletions
diff --git a/email_helpers.py b/email_helpers.py new file mode 100644 index 0000000..15d69a2 --- /dev/null +++ b/email_helpers.py @@ -0,0 +1,141 @@ +from apiclient.discovery import build +from apiclient import errors +from httplib2 import Http +import oauth2client +from oauth2client import client, tools +import os +import json +import base64 +from email.message import EmailMessage +import email +from email.utils import parseaddr, parsedate_to_datetime +import argparse +from bs4 import BeautifulSoup + +SCOPES = 'https://www.googleapis.com/auth/gmail.modify' +CLIENT_SECRET_FILE = os.path.expanduser('~/client_id.json') +APPLICATION_NAME = 'Famille' + +def get_gmail_service(): + """Gets valid user credentials from storage. + + If nothing has been stored, or if the stored credentials are invalid, + the OAuth2 flow is completed to obtain the new credentials. + + Returns: + Credentials, the obtained credential. + """ + credential_dir = os.path.expanduser('~/.credentials') + if not os.path.exists(credential_dir): + os.makedirs(credential_dir) + credential_path = os.path.join(credential_dir, 'news.horel@gmail.com') + store = oauth2client.file.Storage(credential_path) + credentials = store.get() + if not credentials or credentials.invalid: + flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args() + flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES) + flow.user_agent = APPLICATION_NAME + credentials = tools.run_flow(flow, store, flags) + print('Storing credentials to ' + credential_path) + service = build('gmail', 'v1', http=credentials.authorize(Http())) + return service + +class GmailMessage(EmailMessage): + _service = get_gmail_service() + + def msgdict(self): + return {'raw': base64.urlsafe_b64encode(self.as_bytes()).decode()} + + def send(self): + try: + message = (self._service.users().messages(). + send(userId='me',body=self.msgdict()) + .execute()) + print('Message Id: %s' % message['id']) + except errors.HttpError as error: + print('An error occurred: %s' % error) + + @classmethod + def from_id(cls, msg_id, user_id='me'): + try: + message = (cls._service.users().messages(). + get(userId=user_id, id=msg_id, format='raw').execute()) + return email.message_from_bytes( + base64.urlsafe_b64decode(message['raw']), + policy=email.policy.EmailPolicy()) + except errors.HttpError as error: + print(json.loads(error.content.decode('utf-8'))['error']['message']) + +def ListMessagesWithLabels(service, user_id, label_ids=[]): + """List all Messages of the user's mailbox with label_ids applied. + + Args: + service: Authorized Gmail API service instance. + user_id: User's email address. The special value "me" + can be used to indicate the authenticated user. + label_ids: Only return Messages with these labelIds applied. + + Returns: + List of Messages that have all required Labels applied. Note that the + returned list contains Message IDs, you must use get with the + appropriate id to get the details of a Message. + """ + try: + response = service.users().messages().list(userId=user_id, + labelIds=label_ids).execute() + messages = [] + if 'messages' in response: + messages.extend(response['messages']) + while 'nextPageToken' in response: + page_token = response['nextPageToken'] + response = service.users().messages().list(userId=user_id, + labelIds=label_ids, + pageToken=page_token).execute() + messages.extend(response['messages']) + + return messages + except errors.HttpError as error: + print(json.loads(error.content.decode('utf-8'))['error']['message']) + +def labels_dict(service, user_id): + """Returns a dictionary mapping labels to labelids. + + Args: + service: Authorized Gmail API service instance. + user_id: User's email address. The special value "me" + + Returns: + dictionary mapping labels to labelids. + """ + try: + response = service.users().labels().list(userId=user_id).execute() + labels = response['labels'] + return {label['name']: label['id'] for label in labels} + except errors.HttpError as error: + print(json.loads(error.content.decode('utf-8'))['error']['message']) + +def extract_response(content): + soup = BeautifulSoup(content, 'lxml') + reply = soup.find('div', dir='ltr') + return reply + +if __name__ == "__main__": + import re + regex = re.compile("[^+]*\+([^@]*)") + for msg_id in ListMessagesWithLabels(GmailMessage._service, 'me', 'INBOX'): + mail = GmailMessage.from_id(msg_id['id']) + _, email_addr = parseaddr(mail['From']) + m = regex.match(mail['To']) + if m: + body = mail.get_body() + if body.get_content_type() == 'text/html': + comment_cache = extract_response(body.get_content()) + comment = comment_cache.get_text() + elif body.get_content_type() == 'text/plain': + comment = comment_cache = body.get_content() + news_id = m.groups()[0] + date = parsedate_to_datetime(mail['Date']) + sql_str = "INSERT INTO comments(date, user_id, content, news_id, content_cache) " + "VALUES(?, ?, ?, ?)" + db.execute(sql_str, (date, user_id, comment.get_text(), news_id, comment) + print(msg_id['id'], news_id, email_addr, date, comment) @@ -11,10 +11,9 @@ from datetime import datetime import time from email import utils from bs4 import BeautifulSoup -from flask_mail import Mail, Message import locale from smartypants import smartypants, Attr - +from email_helpers import GmailEmailMessage locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8') @@ -27,7 +26,6 @@ def rstify(string): # configuration app = Flask(__name__) app.config.from_envvar('CONF') -mail = Mail(app) @app.template_filter('shortify') def shortify(string): @@ -97,7 +95,6 @@ def get_db(): g.timezone = pytz.common_timezones return db - @app.teardown_appcontext def close_db(error): """Closes the database again at the end of the request.""" @@ -152,15 +149,18 @@ def add_news(): emails = query_db("SELECT email from users where notify=1") emails = [email["email"] for email in emails if email["email"]] if emails: - message = Message(request.form['title'], - sender="news.horel@gmail.com") - message.html = content_cache + message = GmailEmailMessage() + message['to'] = emails + message['subject'] = request.form['title'] + message['reply-to'] = "news.horel+{}@gmail.com".format(news_id) + message.set_content(content) url = url_for('show_news', news_id=news_id, _external=True) - message.html += ("<p style='margin-top:2em'>Vous pouvez " - "<a href='{0}'>Lire cette nouvelle</a> " - "sur le site de la famille.</p>").format(url) - message.recipients = emails - mail.send(message) + html_content = content_cache + + ("<p style='margin-top:2em'>Vous pouvez " + "<a href='{0}'>Lire cette nouvelle</a> " + "sur le site de la famille.</p>").format(url) + message.add_alternative(html_content, subtype='html') + message.send() return redirect(url_for('show_news', news_id=news_id)) else: |
