Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit89a51e8

Browse files
committed
add gmail api tutorial
1 parent067e76d commit89a51e8

File tree

10 files changed

+812
-0
lines changed

10 files changed

+812
-0
lines changed

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
130130
-[How to Make a URL Shortener in Python](https://www.thepythoncode.com/article/make-url-shortener-in-python). ([code](general/url-shortener))
131131
-[How to Get Google Page Ranking in Python](https://www.thepythoncode.com/article/get-google-page-ranking-by-keyword-in-python). ([code](general/getting-google-page-ranking))
132132
-[How to Make a Telegram Bot in Python](https://www.thepythoncode.com/article/make-a-telegram-bot-in-python). ([code](general/telegram-bot))
133+
-[How to Use Gmail API in Python](https://www.thepythoncode.com/article/use-gmail-api-in-python). ([code](general/gmail-api))
133134

134135
-###[Database](https://www.thepythoncode.com/topic/using-databases-in-python)
135136
-[How to Use MySQL Database in Python](https://www.thepythoncode.com/article/using-mysql-database-in-python). ([code](database/mysql-connector))

‎general/gmail-api/README.md‎

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#[How to Use Gmail API in Python](https://www.thepythoncode.com/article/use-gmail-api-in-python)
2+
To use the scripts here:
3+
- Create your credentials file in Google API dashboard and putting it in the current directory, follow[this tutorial](https://www.thepythoncode.com/article/use-gmail-api-in-python) for detailed information.
4+
-`pip3 install -r requirements.txt`
5+
- Change`our_email` variable in`common.py` to your gmail address.
6+
- To send emails, use the`send_emails.py` script:
7+
```
8+
python send_emails.py --help
9+
```
10+
**Output:**
11+
```
12+
usage: send_emails.py [-h] [-f FILES [FILES ...]] destination subject body
13+
14+
Email Sender using Gmail API
15+
16+
positional arguments:
17+
destination The destination email address
18+
subject The subject of the email
19+
body The body of the email
20+
21+
optional arguments:
22+
-h, --help show this help message and exit
23+
-f FILES [FILES ...], --files FILES [FILES ...]
24+
email attachments
25+
```
26+
For example, sending to example@domain.com:
27+
```
28+
python send_emails.py example@domain.com "This is a subject" "Body of the email" --files file1.pdf file2.txt file3.img
29+
```
30+
- To read emails, use the `read_emails.py` script. Downloading & parsing emails for Python related emails:
31+
```
32+
python read_emails.py "python"
33+
```
34+
This will output basic information on all matched emails and creates a folder for each email along with attachments and HTML version of the emails.
35+
- To mark emails as **read** or **unread**, consider using `mark_emails.py`:
36+
```
37+
python mark_emails.py --help
38+
```
39+
**Output**:
40+
```
41+
usage: mark_emails.py [-h] [-r] [-u] query
42+
43+
Marks a set of emails as read or unread
44+
45+
positional arguments:
46+
query a search query that selects emails to mark
47+
48+
optional arguments:
49+
-h, --help show this help message and exit
50+
-r, --read Whether to mark the message as read
51+
-u, --unread Whether to mark the message as unread
52+
```
53+
Marking emails from **Google Alerts** as **Read**:
54+
```
55+
python mark_emails.py "Google Alerts" --read
56+
```
57+
Marking emails sent from example@domain.com as **Unread**:
58+
```
59+
python mark_emails.py "example@domain.com" -u
60+
```
61+
- To delete emails, consider using `delete_emails.py` script, e.g: for deleting emails about Bitcoin:
62+
```
63+
python delete_emails.py "bitcoin"
64+
```
65+
- If you want the full code, consider using `tutorial.ipynb` file.
66+
- Or if you want a all-in-one script, `gmail_api.py` is here as well!

‎general/gmail-api/common.py‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
importos
2+
importpickle
3+
# Gmail API utils
4+
fromgoogleapiclient.discoveryimportbuild
5+
fromgoogle_auth_oauthlib.flowimportInstalledAppFlow
6+
fromgoogle.auth.transport.requestsimportRequest
7+
8+
# Request all access (permission to read/send/receive emails, manage the inbox, and more)
9+
SCOPES= ['https://mail.google.com/']
10+
our_email='our_email@gmail.com'
11+
12+
13+
defgmail_authenticate():
14+
creds=None
15+
# the file token.pickle stores the user's access and refresh tokens, and is
16+
# created automatically when the authorization flow completes for the first time
17+
ifos.path.exists("token.pickle"):
18+
withopen("token.pickle","rb")astoken:
19+
creds=pickle.load(token)
20+
# if there are no (valid) credentials availablle, let the user log in.
21+
ifnotcredsornotcreds.valid:
22+
ifcredsandcreds.expiredandcreds.refresh_token:
23+
creds.refresh(Request())
24+
else:
25+
flow=InstalledAppFlow.from_client_secrets_file('credentials.json',SCOPES)
26+
creds=flow.run_local_server(port=0)
27+
# save the credentials for the next run
28+
withopen("token.pickle","wb")astoken:
29+
pickle.dump(creds,token)
30+
returnbuild('gmail','v1',credentials=creds)
31+
32+
33+
defsearch_messages(service,query):
34+
result=service.users().messages().list(userId='me',q=query).execute()
35+
messages= [ ]
36+
if'messages'inresult:
37+
messages.extend(result['messages'])
38+
while'nextPageToken'inresult:
39+
page_token=result['nextPageToken']
40+
result=service.users().messages().list(userId='me',q=query,pageToken=page_token).execute()
41+
if'messages'inresult:
42+
messages.extend(result['messages'])
43+
returnmessages

‎general/gmail-api/delete_emails.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
fromcommonimportgmail_authenticate,search_messages
2+
3+
defdelete_messages(service,query):
4+
messages_to_delete=search_messages(service,query)
5+
# it's possible to delete a single message with the delete API, like this:
6+
# service.users().messages().delete(userId='me', id=msg['id'])
7+
# but it's also possible to delete all the selected messages with one query, batchDelete
8+
returnservice.users().messages().batchDelete(
9+
userId='me',
10+
body={
11+
'ids': [msg['id']formsginmessages_to_delete]
12+
}
13+
).execute()
14+
15+
if__name__=="__main__":
16+
importsys
17+
service=gmail_authenticate()
18+
delete_messages(service,sys.argv[1])

‎general/gmail-api/gmail_api.py‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# for parsing commandline arguments
2+
importargparse
3+
fromcommonimportsearch_messages,gmail_authenticate
4+
fromread_emailsimportread_message
5+
fromsend_emailsimportsend_message
6+
fromdelete_emailsimportdelete_messages
7+
frommark_emailsimportmark_as_read,mark_as_unread
8+
9+
10+
if__name__=='__main__':
11+
parser=argparse.ArgumentParser(description="Send/Search/Delete/Mark messages using gmail's API.")
12+
subparsers=parser.add_subparsers(help='Subcommands')
13+
parser_1=subparsers.add_parser('send',help='Send an email')
14+
parser_1.add_argument('destination',type=str,help='The destination email address')
15+
parser_1.add_argument('subject',type=str,help='The subject of the email')
16+
parser_1.add_argument('body',type=str,help='The body of the email')
17+
parser_1.add_argument('files',type=str,help='email attachments',nargs='+')
18+
parser_1.set_defaults(action='send')
19+
parser_2=subparsers.add_parser('delete',help='Delete a set of emails')
20+
parser_2.add_argument('query',type=str,help='a search query that selects emails to delete')
21+
parser_2.set_defaults(action='delete')
22+
parser_3=subparsers.add_parser('mark',help='Marks a set of emails as read or unread')
23+
parser_3.add_argument('query',type=str,help='a search query that selects emails to mark')
24+
parser_3.add_argument('read_status',type=bool,help='Whether to mark the message as unread, or as read')
25+
parser_3.set_defaults(action='mark')
26+
parser_4=subparsers.add_parser('search',help='Marks a set of emails as read or unread')
27+
parser_4.add_argument('query',type=str,help='a search query, which messages to display')
28+
parser_4.set_defaults(action='search')
29+
args=parser.parse_args()
30+
service=gmail_authenticate()
31+
ifargs.action=='send':
32+
# TODO: add attachements
33+
send_message(service,args.destination,args.subject,args.body,args.files)
34+
elifargs.action=='delete':
35+
delete_messages(service,args.query)
36+
elifargs.action=='mark':
37+
print(args.unread_status)
38+
ifargs.read_status:
39+
mark_as_read(service,args.query)
40+
else:
41+
mark_as_unread(service,args.query)
42+
elifargs.action=='search':
43+
results=search_messages(service,args.query)
44+
formsginresults:
45+
read_message(service,msg)

‎general/gmail-api/mark_emails.py‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
fromcommonimportgmail_authenticate,search_messages
2+
3+
defmark_as_read(service,query):
4+
messages_to_mark=search_messages(service,query)
5+
returnservice.users().messages().batchModify(
6+
userId='me',
7+
body={
8+
'ids': [msg['id']formsginmessages_to_mark ],
9+
'removeLabelIds': ['UNREAD']
10+
}
11+
).execute()
12+
13+
defmark_as_unread(service,query):
14+
messages_to_mark=search_messages(service,query)
15+
returnservice.users().messages().batchModify(
16+
userId='me',
17+
body={
18+
'ids': [msg['id']formsginmessages_to_mark ],
19+
'addLabelIds': ['UNREAD']
20+
}
21+
).execute()
22+
23+
if__name__=="__main__":
24+
importargparse
25+
parser=argparse.ArgumentParser(description="Marks a set of emails as read or unread")
26+
parser.add_argument('query',help='a search query that selects emails to mark')
27+
parser.add_argument("-r","--read",action="store_true",help='Whether to mark the message as read')
28+
parser.add_argument("-u","--unread",action="store_true",help='Whether to mark the message as unread')
29+
30+
args=parser.parse_args()
31+
service=gmail_authenticate()
32+
ifargs.read:
33+
mark_as_read(service,args.query)
34+
elifargs.unread:
35+
mark_as_unread(service,args.query)

‎general/gmail-api/read_emails.py‎

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
importos
2+
importsys
3+
# for encoding/decoding messages in base64
4+
frombase64importurlsafe_b64decode
5+
fromcommonimportgmail_authenticate,search_messages
6+
7+
8+
defget_size_format(b,factor=1024,suffix="B"):
9+
"""
10+
Scale bytes to its proper byte format
11+
e.g:
12+
1253656 => '1.20MB'
13+
1253656678 => '1.17GB'
14+
"""
15+
forunitin ["","K","M","G","T","P","E","Z"]:
16+
ifb<factor:
17+
returnf"{b:.2f}{unit}{suffix}"
18+
b/=factor
19+
returnf"{b:.2f}Y{suffix}"
20+
21+
22+
defclean(text):
23+
# clean text for creating a folder
24+
return"".join(cifc.isalnum()else"_"forcintext)
25+
26+
27+
defparse_parts(service,parts,folder_name):
28+
"""
29+
Utility function that parses the content of an email partition
30+
"""
31+
ifparts:
32+
forpartinparts:
33+
filename=part.get("filename")
34+
mimeType=part.get("mimeType")
35+
body=part.get("body")
36+
data=body.get("data")
37+
file_size=body.get("size")
38+
part_headers=part.get("headers")
39+
ifpart.get("parts"):
40+
# recursively call this function when we see that a part
41+
# has parts inside
42+
parse_parts(service,part.get("parts"),folder_name)
43+
ifmimeType=="text/plain":
44+
# if the email part is text plain
45+
ifdata:
46+
text=urlsafe_b64decode(data).decode()
47+
print(text)
48+
elifmimeType=="text/html":
49+
# if the email part is an HTML content
50+
# save the HTML file and optionally open it in the browser
51+
ifnotfilename:
52+
filename="index.html"
53+
filepath=os.path.join(folder_name,filename)
54+
print("Saving HTML to",filepath)
55+
withopen(filepath,"wb")asf:
56+
f.write(urlsafe_b64decode(data))
57+
else:
58+
# attachment other than a plain text or HTML
59+
forpart_headerinpart_headers:
60+
part_header_name=part_header.get("name")
61+
part_header_value=part_header.get("value")
62+
ifpart_header_name=="Content-Disposition":
63+
if"attachment"inpart_header_value:
64+
# we get the attachment ID
65+
# and make another request to get the attachment itself
66+
print("Saving the file:",filename,"size:",get_size_format(file_size))
67+
attachment_id=body.get("attachmentId")
68+
attachment=service.users().messages() \
69+
.attachments().get(id=attachment_id,userId='me',messageId=msg['id']).execute()
70+
data=attachment.get("data")
71+
filepath=os.path.join(folder_name,filename)
72+
ifdata:
73+
withopen(filepath,"wb")asf:
74+
f.write(urlsafe_b64decode(data))
75+
76+
77+
defread_message(service,message_id):
78+
"""
79+
This function takes Gmail API `service` and the given `message_id` and does the following:
80+
- Downloads the content of the email
81+
- Prints email basic information (To, From, Subject & Date) and plain/text parts
82+
- Creates a folder for each email based on the subject
83+
- Downloads text/html content (if available) and saves it under the folder created as index.html
84+
- Downloads any file that is attached to the email and saves it in the folder created
85+
"""
86+
msg=service.users().messages().get(userId='me',id=message_id['id'],format='full').execute()
87+
# parts can be the message body, or attachments
88+
payload=msg['payload']
89+
headers=payload.get("headers")
90+
parts=payload.get("parts")
91+
folder_name="email"
92+
ifheaders:
93+
# this section prints email basic info & creates a folder for the email
94+
forheaderinheaders:
95+
name=header.get("name")
96+
value=header.get("value")
97+
ifname=='From':
98+
# we print the From address
99+
print("From:",value)
100+
ifname=="To":
101+
# we print the To address
102+
print("To:",value)
103+
ifname=="Subject":
104+
# make a directory with the name of the subject
105+
folder_name=clean(value)
106+
# we will also handle emails with the same subject name
107+
folder_counter=0
108+
whileos.path.isdir(folder_name):
109+
folder_counter+=1
110+
# we have the same folder name, add a number next to it
111+
iffolder_name[-1].isdigit()andfolder_name[-2]=="_":
112+
folder_name=f"{folder_name[:-2]}_{folder_counter}"
113+
eliffolder_name[-2:].isdigit()andfolder_name[-3]=="_":
114+
folder_name=f"{folder_name[:-3]}_{folder_counter}"
115+
else:
116+
folder_name=f"{folder_name}_{folder_counter}"
117+
os.mkdir(folder_name)
118+
print("Subject:",value)
119+
ifname=="Date":
120+
# we print the date when the message was sent
121+
print("Date:",value)
122+
123+
parse_parts(service,parts,folder_name)
124+
print("="*50)
125+
126+
if__name__=="__main__":
127+
service=gmail_authenticate()
128+
# get emails that match the query you specify from the command lines
129+
results=search_messages(service,sys.argv[1])
130+
# for each email matched, read it (output plain/text to console & save HTML and attachments)
131+
formsginresults:
132+
read_message(service,msg)

‎general/gmail-api/requirements.txt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
google-api-python-client
2+
google-auth-httplib2
3+
google-auth-oauthlib

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp