{"action":"created","comment":{"url":"https://api.github.com/repos/zulip/zulip/pulls/comments/95298851","pull_request_review_id":15848126,"id":95298851,"diff_hunk":"@@ -0,0 +1,163 @@\n+#instructions to install googleapiclient can be found in this bot's readme file.\n+from __future__ import print_function\n+import base64\n+import httplib2\n+import logging\n+import mimetypes\n+import os\n+import re\n+\n+from googleapiclient import discovery, errors\n+from email.mime.text import MIMEText\n+from oauth2client.file import Storage\n+\n+class GmailHandler(object):\n+    '''\n+    This plugin facilitates sending emails from a Gmail account\n+    from within Zulip. It looks for messages starting with '@gmail'.\n+    '''\n+\n+    def usage(self):\n+        return '''\n+            This plugin will allow users to send emails from a\n+            personal gmail account. Users should preface\n+            messages with \"@gmail\".\n+\n+            Enter messages in the following format:\n+            '@gmail <recipient_email> \"<subject>\" \"<body>\" --label <label>'\n+            The --label tag is optional and can be left out.\n+            '''\n+\n+    def triage_message(self, message, client):\n+        # return True if we want to (possibly) response to this message\n+\n+        original_content = message['content']\n+        self.bot_email = client.email\n+\n+        # This next line of code is defensive\n+        if message['display_recipient'] == 'gmail':\n+            return False\n+        return original_content.startswith('@gmail')\n+\n+    def handle_message(self, message, client, state_handler):\n+        original_content = message['content']\n+        original_sender = message['sender_email']\n+\n+        try:\n+            recipient, subject, body, label = parse_input(original_content)\n+        except ValueError:\n+            recipient, subject, body = parse_input(original_content)\n+            label = False\n+        except TypeError:\n+            raise Exception(\"The input format used was incorrect. The correct format is: \"\n+                            '@gmail <recipient> \"<subject>\" \"<body>\"')\n+\n+        service = get_service()\n+        email = create_message(body, subject, recipient)\n+        result = send_message(service, email)\n+\n+        label_result = False\n+        if label:\n+            create_label(service, label)\n+            label_id = get_label_id(service, label)\n+            label_result = add_label(service, label_id, result['id'])\n+\n+        if 'SENT' in result['labelIds']:\n+            content = 'Email sent to {}'.format(recipient)\n+            if label_result:  # Enters this block if the label couldn't be added\n+                              # or if there was no label\n+                content += ' without label.'\n+            else:\n+                content += '.'\n+        else:\n+            content = 'Could not send email to {}. Please try again.'.format(recipient)\n+\n+        client.send_message(dict(\n+            type = 'private',\n+            to = original_sender,\n+            sender = self.bot_email,\n+            content = content\n+        ))\n+\n+\n+def parse_input(user_input):\n+    # Input is of the following format: (--label flag is optional)\n+    # @gmail <recipient_email> \"<subject>\" \"<body>\" --label <label>\n+    if '--label' in user_input:\n+        regex = '@gmail (.*?) \"(.*?)\" \"(.*?)\" --label (.*?)\\Z'","path":"contrib_bots/lib/gmail.py","position":87,"original_position":87,"commit_id":"f1ea313cba9c17506f8cff1bbf63a9973d6d72a1","original_commit_id":"f1ea313cba9c17506f8cff1bbf63a9973d6d72a1","user":{"login":"umairwaheed","id":641763,"avatar_url":"https://avatars.githubusercontent.com/u/641763?v=3","gravatar_id":"","url":"https://api.github.com/users/umairwaheed","html_url":"https://github.com/umairwaheed","followers_url":"https://api.github.com/users/umairwaheed/followers","following_url":"https://api.github.com/users/umairwaheed/following{/other_user}","gists_url":"https://api.github.com/users/umairwaheed/gists{/gist_id}","starred_url":"https://api.github.com/users/umairwaheed/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/umairwaheed/subscriptions","organizations_url":"https://api.github.com/users/umairwaheed/orgs","repos_url":"https://api.github.com/users/umairwaheed/repos","events_url":"https://api.github.com/users/umairwaheed/events{/privacy}","received_events_url":"https://api.github.com/users/umairwaheed/received_events","type":"User","site_admin":false},"body":"You can compile  these regexes as well. It's up to you though. Do the compilation in `__init__`:\r\n```Python\r\ndef __init__(self):\r\n    self.parse_regex_with_label = re.compile('@gmail (.*?) \"(.*?)\" \"(.*?)\" --label (.*?)\\Z')\r\n    self.parse_regex = re.compile('@gmail (.*?) \"(.*?)\" \"(.*?)\"\\Z')\r\n\r\ndef parse_input(user_input):\r\n    regex = self.parse_regex\r\n    if \"--label\" in user_input:\r\n        regex = self.parse_regex_with_label\r\n    match = regex.match(user_input)\r\n```","created_at":"2017-01-10T04:31:19Z","updated_at":"2017-01-10T04:31:19Z","html_url":"https://github.com/zulip/zulip/pull/2951#discussion_r95298851","pull_request_url":"https://api.github.com/repos/zulip/zulip/pulls/2951","_links":{"self":{"href":"https://api.github.com/repos/zulip/zulip/pulls/comments/95298851"},"html":{"href":"https://github.com/zulip/zulip/pull/2951#discussion_r95298851"},"pull_request":{"href":"https://api.github.com/repos/zulip/zulip/pulls/2951"}}},"pull_request":{"url":"https://api.github.com/repos/zulip/zulip/pulls/2951","id":99498688,"html_url":"https://github.com/zulip/zulip/pull/2951","diff_url":"https://github.com/zulip/zulip/pull/2951.diff","patch_url":"https://github.com/zulip/zulip/pull/2951.patch","issue_url":"https://api.github.com/repos/zulip/zulip/issues/2951","number":2951,"state":"open","locked":false,"title":"Add interactive Gmail bot","user":{"login":"fazerlicourice7","id":10129077,"avatar_url":"https://avatars.githubusercontent.com/u/10129077?v=3","gravatar_id":"","url":"https://api.github.com/users/fazerlicourice7","html_url":"https://github.com/fazerlicourice7","followers_url":"https://api.github.com/users/fazerlicourice7/followers","following_url":"https://api.github.com/users/fazerlicourice7/following{/other_user}","gists_url":"https://api.github.com/users/fazerlicourice7/gists{/gist_id}","starred_url":"https://api.github.com/users/fazerlicourice7/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fazerlicourice7/subscriptions","organizations_url":"https://api.github.com/users/fazerlicourice7/orgs","repos_url":"https://api.github.com/users/fazerlicourice7/repos","events_url":"https://api.github.com/users/fazerlicourice7/events{/privacy}","received_events_url":"https://api.github.com/users/fazerlicourice7/received_events","type":"User","site_admin":false},"body":"Add a bot that lets you send emails(from a gmail account) through Zulip.","created_at":"2016-12-28T01:26:00Z","updated_at":"2017-01-10T04:31:19Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6e8ce84a60356b531331ca3d06ad031141587923","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/zulip/zulip/pulls/2951/commits","review_comments_url":"https://api.github.com/repos/zulip/zulip/pulls/2951/comments","review_comment_url":"https://api.github.com/repos/zulip/zulip/pulls/comments{/number}","comments_url":"https://api.github.com/repos/zulip/zulip/issues/2951/comments","statuses_url":"https://api.github.com/repos/zulip/zulip/statuses/f1ea313cba9c17506f8cff1bbf63a9973d6d72a1","head":{"label":"fazerlicourice7:gmail_bot","ref":"gmail_bot","sha":"f1ea313cba9c17506f8cff1bbf63a9973d6d72a1","user":{"login":"fazerlicourice7","id":10129077,"avatar_url":"https://avatars.githubusercontent.com/u/10129077?v=3","gravatar_id":"","url":"https://api.github.com/users/fazerlicourice7","html_url":"https://github.com/fazerlicourice7","followers_url":"https://api.github.com/users/fazerlicourice7/followers","following_url":"https://api.github.com/users/fazerlicourice7/following{/other_user}","gists_url":"https://api.github.com/users/fazerlicourice7/gists{/gist_id}","starred_url":"https://api.github.com/users/fazerlicourice7/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fazerlicourice7/subscriptions","organizations_url":"https://api.github.com/users/fazerlicourice7/orgs","repos_url":"https://api.github.com/users/fazerlicourice7/repos","events_url":"https://api.github.com/users/fazerlicourice7/events{/privacy}","received_events_url":"https://api.github.com/users/fazerlicourice7/received_events","type":"User","site_admin":false},"repo":{"id":75024716,"name":"zulip","full_name":"fazerlicourice7/zulip","owner":{"login":"fazerlicourice7","id":10129077,"avatar_url":"https://avatars.githubusercontent.com/u/10129077?v=3","gravatar_id":"","url":"https://api.github.com/users/fazerlicourice7","html_url":"https://github.com/fazerlicourice7","followers_url":"https://api.github.com/users/fazerlicourice7/followers","following_url":"https://api.github.com/users/fazerlicourice7/following{/other_user}","gists_url":"https://api.github.com/users/fazerlicourice7/gists{/gist_id}","starred_url":"https://api.github.com/users/fazerlicourice7/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fazerlicourice7/subscriptions","organizations_url":"https://api.github.com/users/fazerlicourice7/orgs","repos_url":"https://api.github.com/users/fazerlicourice7/repos","events_url":"https://api.github.com/users/fazerlicourice7/events{/privacy}","received_events_url":"https://api.github.com/users/fazerlicourice7/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/fazerlicourice7/zulip","description":"Zulip server - powerful open source group chat","fork":true,"url":"https://api.github.com/repos/fazerlicourice7/zulip","forks_url":"https://api.github.com/repos/fazerlicourice7/zulip/forks","keys_url":"https://api.github.com/repos/fazerlicourice7/zulip/keys{/key_id}","collaborators_url":"https://api.github.com/repos/fazerlicourice7/zulip/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/fazerlicourice7/zulip/teams","hooks_url":"https://api.github.com/repos/fazerlicourice7/zulip/hooks","issue_events_url":"https://api.github.com/repos/fazerlicourice7/zulip/issues/events{/number}","events_url":"https://api.github.com/repos/fazerlicourice7/zulip/events","assignees_url":"https://api.github.com/repos/fazerlicourice7/zulip/assignees{/user}","branches_url":"https://api.github.com/repos/fazerlicourice7/zulip/branches{/branch}","tags_url":"https://api.github.com/repos/fazerlicourice7/zulip/tags","blobs_url":"https://api.github.com/repos/fazerlicourice7/zulip/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/fazerlicourice7/zulip/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/fazerlicourice7/zulip/git/refs{/sha}","trees_url":"https://api.github.com/repos/fazerlicourice7/zulip/git/trees{/sha}","statuses_url":"https://api.github.com/repos/fazerlicourice7/zulip/statuses/{sha}","languages_url":"https://api.github.com/repos/fazerlicourice7/zulip/languages","stargazers_url":"https://api.github.com/repos/fazerlicourice7/zulip/stargazers","contributors_url":"https://api.github.com/repos/fazerlicourice7/zulip/contributors","subscribers_url":"https://api.github.com/repos/fazerlicourice7/zulip/subscribers","subscription_url":"https://api.github.com/repos/fazerlicourice7/zulip/subscription","commits_url":"https://api.github.com/repos/fazerlicourice7/zulip/commits{/sha}","git_commits_url":"https://api.github.com/repos/fazerlicourice7/zulip/git/commits{/sha}","comments_url":"https://api.github.com/repos/fazerlicourice7/zulip/comments{/number}","issue_comment_url":"https://api.github.com/repos/fazerlicourice7/zulip/issues/comments{/number}","contents_url":"https://api.github.com/repos/fazerlicourice7/zulip/contents/{+path}","compare_url":"https://api.github.com/repos/fazerlicourice7/zulip/compare/{base}...{head}","merges_url":"https://api.github.com/repos/fazerlicourice7/zulip/merges","archive_url":"https://api.github.com/repos/fazerlicourice7/zulip/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/fazerlicourice7/zulip/downloads","issues_url":"https://api.github.com/repos/fazerlicourice7/zulip/issues{/number}","pulls_url":"https://api.github.com/repos/fazerlicourice7/zulip/pulls{/number}","milestones_url":"https://api.github.com/repos/fazerlicourice7/zulip/milestones{/number}","notifications_url":"https://api.github.com/repos/fazerlicourice7/zulip/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/fazerlicourice7/zulip/labels{/name}","releases_url":"https://api.github.com/repos/fazerlicourice7/zulip/releases{/id}","deployments_url":"https://api.github.com/repos/fazerlicourice7/zulip/deployments","created_at":"2016-11-28T23:53:27Z","updated_at":"2016-11-28T23:53:35Z","pushed_at":"2017-01-10T02:13:11Z","git_url":"git://github.com/fazerlicourice7/zulip.git","ssh_url":"git@github.com:fazerlicourice7/zulip.git","clone_url":"https://github.com/fazerlicourice7/zulip.git","svn_url":"https://github.com/fazerlicourice7/zulip","homepage":"","size":134935,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"zulip:master","ref":"master","sha":"764a54ae2650f4b9db440f1aff615a38118ac3f5","user":{"login":"zulip","id":4921959,"avatar_url":"https://avatars.githubusercontent.com/u/4921959?v=3","gravatar_id":"","url":"https://api.github.com/users/zulip","html_url":"https://github.com/zulip","followers_url":"https://api.github.com/users/zulip/followers","following_url":"https://api.github.com/users/zulip/following{/other_user}","gists_url":"https://api.github.com/users/zulip/gists{/gist_id}","starred_url":"https://api.github.com/users/zulip/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zulip/subscriptions","organizations_url":"https://api.github.com/users/zulip/orgs","repos_url":"https://api.github.com/users/zulip/repos","events_url":"https://api.github.com/users/zulip/events{/privacy}","received_events_url":"https://api.github.com/users/zulip/received_events","type":"Organization","site_admin":false},"repo":{"id":43160685,"name":"zulip","full_name":"zulip/zulip","owner":{"login":"zulip","id":4921959,"avatar_url":"https://avatars.githubusercontent.com/u/4921959?v=3","gravatar_id":"","url":"https://api.github.com/users/zulip","html_url":"https://github.com/zulip","followers_url":"https://api.github.com/users/zulip/followers","following_url":"https://api.github.com/users/zulip/following{/other_user}","gists_url":"https://api.github.com/users/zulip/gists{/gist_id}","starred_url":"https://api.github.com/users/zulip/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zulip/subscriptions","organizations_url":"https://api.github.com/users/zulip/orgs","repos_url":"https://api.github.com/users/zulip/repos","events_url":"https://api.github.com/users/zulip/events{/privacy}","received_events_url":"https://api.github.com/users/zulip/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/zulip/zulip","description":"Zulip server - powerful open source group chat","fork":false,"url":"https://api.github.com/repos/zulip/zulip","forks_url":"https://api.github.com/repos/zulip/zulip/forks","keys_url":"https://api.github.com/repos/zulip/zulip/keys{/key_id}","collaborators_url":"https://api.github.com/repos/zulip/zulip/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/zulip/zulip/teams","hooks_url":"https://api.github.com/repos/zulip/zulip/hooks","issue_events_url":"https://api.github.com/repos/zulip/zulip/issues/events{/number}","events_url":"https://api.github.com/repos/zulip/zulip/events","assignees_url":"https://api.github.com/repos/zulip/zulip/assignees{/user}","branches_url":"https://api.github.com/repos/zulip/zulip/branches{/branch}","tags_url":"https://api.github.com/repos/zulip/zulip/tags","blobs_url":"https://api.github.com/repos/zulip/zulip/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/zulip/zulip/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/zulip/zulip/git/refs{/sha}","trees_url":"https://api.github.com/repos/zulip/zulip/git/trees{/sha}","statuses_url":"https://api.github.com/repos/zulip/zulip/statuses/{sha}","languages_url":"https://api.github.com/repos/zulip/zulip/languages","stargazers_url":"https://api.github.com/repos/zulip/zulip/stargazers","contributors_url":"https://api.github.com/repos/zulip/zulip/contributors","subscribers_url":"https://api.github.com/repos/zulip/zulip/subscribers","subscription_url":"https://api.github.com/repos/zulip/zulip/subscription","commits_url":"https://api.github.com/repos/zulip/zulip/commits{/sha}","git_commits_url":"https://api.github.com/repos/zulip/zulip/git/commits{/sha}","comments_url":"https://api.github.com/repos/zulip/zulip/comments{/number}","issue_comment_url":"https://api.github.com/repos/zulip/zulip/issues/comments{/number}","contents_url":"https://api.github.com/repos/zulip/zulip/contents/{+path}","compare_url":"https://api.github.com/repos/zulip/zulip/compare/{base}...{head}","merges_url":"https://api.github.com/repos/zulip/zulip/merges","archive_url":"https://api.github.com/repos/zulip/zulip/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/zulip/zulip/downloads","issues_url":"https://api.github.com/repos/zulip/zulip/issues{/number}","pulls_url":"https://api.github.com/repos/zulip/zulip/pulls{/number}","milestones_url":"https://api.github.com/repos/zulip/zulip/milestones{/number}","notifications_url":"https://api.github.com/repos/zulip/zulip/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/zulip/zulip/labels{/name}","releases_url":"https://api.github.com/repos/zulip/zulip/releases{/id}","deployments_url":"https://api.github.com/repos/zulip/zulip/deployments","created_at":"2015-09-25T16:37:25Z","updated_at":"2017-01-10T02:20:18Z","pushed_at":"2017-01-10T04:29:38Z","git_url":"git://github.com/zulip/zulip.git","ssh_url":"git@github.com:zulip/zulip.git","clone_url":"https://github.com/zulip/zulip.git","svn_url":"https://github.com/zulip/zulip","homepage":"","size":135046,"stargazers_count":4369,"watchers_count":4369,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":974,"mirror_url":null,"open_issues_count":704,"forks":974,"open_issues":704,"watchers":4369,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/zulip/zulip/pulls/2951"},"html":{"href":"https://github.com/zulip/zulip/pull/2951"},"issue":{"href":"https://api.github.com/repos/zulip/zulip/issues/2951"},"comments":{"href":"https://api.github.com/repos/zulip/zulip/issues/2951/comments"},"review_comments":{"href":"https://api.github.com/repos/zulip/zulip/pulls/2951/comments"},"review_comment":{"href":"https://api.github.com/repos/zulip/zulip/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/zulip/zulip/pulls/2951/commits"},"statuses":{"href":"https://api.github.com/repos/zulip/zulip/statuses/f1ea313cba9c17506f8cff1bbf63a9973d6d72a1"}}}}
{"actor":{"display_login":"umairwaheed"}}