-
-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d830143
commit 76e151c
Showing
9 changed files
with
850 additions
and
223 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,18 +7,47 @@ Current Supported Behavior: | |
* Sending messages with attachments | ||
* Sending messages with your Gmail account signature | ||
* Retrieving messages with the full suite of Gmail's search capabilities | ||
* Retrieving messages with attachments, and downloading attachments | ||
* Modifying message labels (includes marking as read/unread, important/not | ||
important, starred/unstarred, trash/untrash, inbox/archive) | ||
|
||
## Getting Started | ||
The only setup required is to download a "client secrets" file from Google that will allow your applications to do its thing. | ||
The only setup required is to download an OAuth 2.0 Client ID file from Google | ||
that will authorize your application. | ||
|
||
Follow the instructions here: https://developers.google.com/gmail/api/quickstart/python. | ||
This can be done at: https://console.developers.google.com/apis/credentials. | ||
For those who haven't created a credential for Google's API, after clicking the | ||
link above (and logging in to the appropriate account), | ||
|
||
Name the file you download "client_secrets.json" and place it in the root directory of your application. | ||
1. Select/create the project that this authentication is for (if creating a new | ||
project make sure to configure the OAuth consent screen; you only need to set | ||
an Application name). | ||
|
||
The first time you create a new instance of the `Gmail` class, a browser window will open and you'll be asked to give permissions to the application. This will only happen once. | ||
2. Click on the "Dashboard" tab, then "Enable APIs and Services". Search for | ||
Gmail and enable. | ||
|
||
3. Click on the Credentials tab, then "Create Credentials" > "OAuth client ID". | ||
|
||
4. Select what kind of application this is for, and give it a memorable name. | ||
|
||
5. Back on the credentials screen, click the download icon next to the | ||
credential you just created to download it as a JSON object. | ||
|
||
6. Save this file as "client_secret.json" and place it in the root directory of | ||
your application. (The `Gmail` class takes in an argument for the name of this | ||
file if you choose to name it otherwise.) | ||
|
||
The first time you create a new instance of the `Gmail` class, a browser window | ||
will open, and you'll be asked to give permissions to the application. This | ||
will save an access token in a file named "gmail-token.json", and only needs to | ||
occur once. | ||
|
||
You are now good to go! | ||
|
||
Note about authentication method: I have opted not to use a username-password | ||
authentication (through imap/smtp), since using Google's authorization is both | ||
significantly safer and avoids clashing with Google's many security measures. | ||
|
||
## Usage | ||
### Send a simple message: | ||
```python | ||
|
@@ -34,7 +63,7 @@ params = { | |
"msg_plain": "Hi\nThis is a plain text email.", | ||
"signature": True # use my account signature | ||
} | ||
gmail.send_message(**params) # equivalent to send_message(to="[email protected]", sender=...) | ||
message = gmail.send_message(**params) # equivalent to send_message(to="[email protected]", sender=...) | ||
``` | ||
|
||
### Send a message with attachments, cc, bcc fields: | ||
|
@@ -54,7 +83,7 @@ params = { | |
"attachments": ["path/to/something/cool.pdf", "path/to/image.jpg", "path/to/script.py"], | ||
"signature": True # use my account signature | ||
} | ||
gmail.send_message(**params) # equivalent to send_message(to="[email protected]", sender=...) | ||
message = gmail.send_message(**params) # equivalent to send_message(to="[email protected]", sender=...) | ||
``` | ||
|
||
It couldn't be easier! | ||
|
@@ -71,17 +100,57 @@ messages = gmail.get_unread_inbox() | |
# Starred messages | ||
messages = gmail.get_starred_messages() | ||
|
||
# ...and many more easy to use functions... | ||
# ...and many more easy to use functions can be found in gmail.py! | ||
|
||
# Print them out! | ||
for message in messages: | ||
print("To: " + message['To']) | ||
print("From: " + message['From']) | ||
print("Subject: " + message['Subject']) | ||
print("Date: " + message['Date']) | ||
print("Preview: " + message['Snippet']) | ||
print("To: " + message.recipient) | ||
print("From: " + message.sender) | ||
print("Subject: " + message.subject) | ||
print("Date: " + message.date) | ||
print("Preview: " + message.snippet) | ||
|
||
# print("Message Body: " + message['Message Body']) | ||
print("Message Body: " + message.plain) # or message.html | ||
``` | ||
|
||
### Marking messages: | ||
```python | ||
from simplegmail import Gmail | ||
|
||
gmail = Gmail() | ||
|
||
messages = gmail.get_unread_inbox() | ||
|
||
message_to_read = messages[0] | ||
message_to_read.mark_as_read() | ||
|
||
# Oops, I want to mark as unread now | ||
message_to_read.mark_as_unread() | ||
|
||
message_to_star = messages[1] | ||
message_to_star.star() | ||
|
||
message_to_trash = messages[2] | ||
message_to_trash.trash() | ||
|
||
# ...and many more functions can be found in message.py! | ||
``` | ||
|
||
### Downloading attachments: | ||
```python | ||
from simplegmail import Gmail | ||
|
||
gmail = Gmail() | ||
|
||
messages = gmail.get_unread_inbox() | ||
|
||
message = messages[0] | ||
if message.attachments: | ||
for attm in message.attachments: | ||
print('File: ' + attm.filename) | ||
attm.save() # downloads and saves each attachment under it's stored | ||
# filename. You can download without saving with `attm.download()` | ||
|
||
``` | ||
|
||
### Retrieving messages (advanced, with queries!): | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,18 +2,20 @@ | |
|
||
setuptools.setup( | ||
name="simplegmail", | ||
version="1.0.0", | ||
url="https://github.com/illiteratecoder/simple-gmail", | ||
version="2.0.0", | ||
url="https://github.com/jeremyephron/simple-gmail", | ||
author="Jeremy Ephron", | ||
author_email="[email protected]", | ||
description="A simple Python API client for Gmail.", | ||
long_description=open('README.md').read(), | ||
long_description_content_type='text/markdown', | ||
packages=setuptools.find_packages(), | ||
install_requires=[ | ||
'google-api-python-client>=1.7.3', | ||
'bs4>=0.0.1', | ||
'py-dateutil>=2.2', | ||
'oauth2client>=4.1.3' | ||
'python-dateutil>=2.8.1', | ||
'oauth2client>=4.1.3', | ||
'lxml>=4.4.2' | ||
], | ||
setup_requires=["pytest-runner"], | ||
tests_require=["pytest"], | ||
|
@@ -24,4 +26,4 @@ | |
"License :: OSI Approved :: MIT License", | ||
"Operating System :: OS Independent", | ||
], | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
from simplegmail.gmail import Gmail | ||
from simplegmail import query | ||
from simplegmail import labels | ||
|
||
__all__ = ['Gmail'] | ||
__all__ = ['Gmail', 'query', 'labels'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
""" | ||
This module contains the implementation of the Attachment object. | ||
""" | ||
|
||
import base64 # for base64.urlsafe_b64decode | ||
import os # for os.path.exists | ||
|
||
class Attachment(object): | ||
""" | ||
The Attachment class for attachments to emails in your Gmail mailbox. This | ||
class should not be manually instantiated. | ||
Args: | ||
service (googleapiclient.discovery.Resource): the Gmail service object. | ||
user_id (str): the username of the account the message belongs to. | ||
msg_id (str): the id of message the attachment belongs to. | ||
att_id (str): the id of the attachment. | ||
filename (str): the filename associated with the attachment. | ||
filetype (str): the mime type of the file. | ||
data (bytes): the raw data of the file. Default None. | ||
Attributes: | ||
_service (googleapiclient.discovery.Resource): the Gmail service object. | ||
user_id (str): the username of the account the message belongs to. | ||
msg_id (str): the id of message the attachment belongs to. | ||
id (str): the id of the attachment. | ||
filename (str): the filename associated with the attachment. | ||
filetype (str): the mime type of the file. | ||
data (bytes): the raw data of the file. | ||
""" | ||
|
||
def __init__(self, service, user_id, msg_id, att_id, filename, filetype, | ||
data=None): | ||
self._service = service | ||
self.user_id = user_id | ||
self.msg_id = msg_id | ||
self.id = att_id | ||
self.filename = filename | ||
self.filetype = filetype | ||
self.data = data | ||
|
||
def download(self): | ||
""" | ||
Downloads the data for an attachment if it does not exist. | ||
""" | ||
|
||
if self.data is not None: | ||
return | ||
|
||
res = self._service.users().messages().attachments().get( | ||
userId=self.user_id, messageId=self.msg_id, id=self.id | ||
).execute() | ||
|
||
data = res['data'] | ||
self.data = base64.urlsafe_b64decode(data) | ||
|
||
def save(self, filepath=None, overwrite=False): | ||
""" | ||
Saves the attachment. Downloads file data if not downloaded. | ||
Args: | ||
filepath (str): where to save the attachment. Default None, which | ||
uses the filename stored. | ||
overwrite (bool): whether to overwrite existing files. Default False. | ||
Raises: | ||
FileExistsError: if the call would overwrite an existing file and | ||
overwrite is not set to True. | ||
""" | ||
|
||
if filepath is None: | ||
filepath = self.filename | ||
|
||
if self.data is None: | ||
self.download() | ||
|
||
if overwrite and os.path.exists(filepath): | ||
raise FileExistsError( | ||
f"Cannot overwrite file '{filepath}'. Use overwrite=True if " | ||
f"you would like to overwrite the file." | ||
) | ||
|
||
with open(filepath, 'wb') as f: | ||
f.write(self.data) | ||
|
Oops, something went wrong.