mirror of
https://github.com/zhayujie/bot-on-anything.git
synced 2026-01-19 09:41:07 +08:00
15
README.md
15
README.md
@@ -17,6 +17,7 @@
|
||||
- [ ] QQ
|
||||
- [ ] 钉钉
|
||||
- [ ] 飞书
|
||||
- [x] Gmail
|
||||
|
||||
# 快速开始
|
||||
|
||||
@@ -217,3 +218,17 @@ Hit Ctrl-C to quit.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Gmail
|
||||
**需要:** 一个服务器、一个Gmail account
|
||||
Follow [官方文档](https://support.google.com/mail/answer/185833?hl=en) to create APP password for google account, config as below, then cheers!!!
|
||||
```json
|
||||
"channel": {
|
||||
"type": "gmail",
|
||||
"gmail": {
|
||||
"subject_keyword": ["bot", "@bot"],
|
||||
"host_email": "xxxx@gmail.com",
|
||||
"host_password": "GMAIL ACCESS KEY"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -25,5 +25,9 @@ def create_channel(channel_type):
|
||||
from channel.wechat.wechat_mp_service_channel import WechatServiceAccount
|
||||
return WechatServiceAccount()
|
||||
|
||||
elif channel_type == const.GMAIL:
|
||||
from channel.gmail.gmail_channel import GmailChannel
|
||||
return GmailChannel()
|
||||
|
||||
else:
|
||||
raise RuntimeError
|
||||
|
||||
180
channel/gmail/gmail_channel.py
Executable file
180
channel/gmail/gmail_channel.py
Executable file
@@ -0,0 +1,180 @@
|
||||
import smtplib
|
||||
import imaplib
|
||||
import email
|
||||
import re
|
||||
import base64
|
||||
import time
|
||||
from random import randrange
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import decode_header
|
||||
from channel.channel import Channel
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from common import const
|
||||
from config import channel_conf_val, channel_conf
|
||||
|
||||
|
||||
smtp_ssl_host = 'smtp.gmail.com: 587'
|
||||
imap_ssl_host = 'imap.gmail.com'
|
||||
MAX_DELAY = 30
|
||||
MIN_DELAY = 15
|
||||
STEP_TIME = 2
|
||||
LATESTN = 5
|
||||
wait_time = 0
|
||||
thread_pool = ThreadPoolExecutor(max_workers=8)
|
||||
|
||||
def checkEmail(email):
|
||||
# regex = '^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'
|
||||
regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
|
||||
if re.search(regex, email):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def process(max, speed):
|
||||
global wait_time
|
||||
i=0
|
||||
while i<=max:
|
||||
i=i+1
|
||||
time.sleep(speed)
|
||||
print("\r"+"Waited: "+str(i+wait_time)+"s", end='')
|
||||
# print("\r"+"==="*int(i-1)+":-)"+"==="*int(max-i)+"$"+str(max)+' waited:'+str(i)+"%", end='')
|
||||
wait_time += max*speed
|
||||
|
||||
class GmailChannel(Channel):
|
||||
def __init__(self):
|
||||
self.host_email = channel_conf_val(const.GMAIL, 'host_email')
|
||||
self.host_password = channel_conf_val(const.GMAIL, 'host_password')
|
||||
# self.addrs_white_list = channel_conf_val(const.GMAIL, 'addrs_white_list')
|
||||
self.subject_keyword = channel_conf_val(const.GMAIL, 'subject_keyword')
|
||||
|
||||
def startup(self):
|
||||
global wait_time
|
||||
ques_list = list()
|
||||
lastques = {'from': None, 'subject': None, 'content': None}
|
||||
print("INFO: let's go...")
|
||||
while(True):
|
||||
ques_list = self.receiveEmail()
|
||||
if ques_list:
|
||||
for ques in ques_list:
|
||||
if ques['subject'] is None:
|
||||
print("WARN: question from:%s is empty " % ques['from'])
|
||||
elif(lastques['subject'] == ques['subject'] and lastques['from'] == ques['from']):
|
||||
print("INFO: this question has already been answered. Q:%s" % (ques['subject']))
|
||||
else:
|
||||
if ques['subject']:
|
||||
print("Nice: a new message coming...", end='\n')
|
||||
self.handle(ques)
|
||||
lastques = ques
|
||||
wait_time = 0
|
||||
else:
|
||||
print("WARN: the question in subject is empty")
|
||||
else:
|
||||
process(randrange(MIN_DELAY, MAX_DELAY), STEP_TIME)
|
||||
|
||||
def handle(self, question):
|
||||
message = dict()
|
||||
context = dict()
|
||||
print("INFO: From: %s Question: %s" % (question['from'], question['subject']))
|
||||
context['from_user_id'] = question['from']
|
||||
answer = super().build_reply_content(question['subject'], context) #get answer from openai
|
||||
message = MIMEText(answer)
|
||||
message['subject'] = question['subject']
|
||||
message['from'] = self.host_email
|
||||
message['to'] = question['from']
|
||||
thread_pool.submit(self.sendEmail, message)
|
||||
|
||||
def sendEmail(self, message: list) -> dict:
|
||||
smtp_server = smtplib.SMTP(smtp_ssl_host)
|
||||
smtp_server.starttls()
|
||||
smtp_server.login(self.host_email, self.host_password)
|
||||
output = {'success': 0, 'failed': 0, 'invalid': 0}
|
||||
try:
|
||||
smtp_server.sendmail(message['from'], message['to'], message.as_string())
|
||||
print("sending to {}".format(message['to']))
|
||||
output['success'] += 1
|
||||
except Exception as e:
|
||||
print("Error: {}".format(e))
|
||||
output['failed'] += 1
|
||||
print("successed:{}, failed:{}".format(output['success'], output['failed']))
|
||||
smtp_server.quit()
|
||||
return output
|
||||
|
||||
def receiveEmail(self):
|
||||
question_list = list()
|
||||
question = {'from': None, 'subject': None, 'content': None}
|
||||
imap_server = imaplib.IMAP4_SSL(imap_ssl_host)
|
||||
imap_server.login(self.host_email, self.host_password)
|
||||
imap_server.select('inbox')
|
||||
status, data = imap_server.search(None, 'ALL')
|
||||
mail_ids = []
|
||||
for block in data:
|
||||
mail_ids += block.split()
|
||||
#only fetch the latest 5 messages
|
||||
mail_ids = mail_ids[-LATESTN:]
|
||||
for i in mail_ids:
|
||||
status, data = imap_server.fetch(i, '(RFC822)')
|
||||
for response in data:
|
||||
if isinstance(response, tuple):
|
||||
message = email.message_from_bytes(response[1])
|
||||
mail_from = message['from'].split('<')[1].replace(">", "")
|
||||
# if mail_from not in self.addrs_white_list:
|
||||
# continue
|
||||
|
||||
#subject do not support chinese
|
||||
mail_subject = decode_header(message['subject'])[0][0]
|
||||
if isinstance(mail_subject, bytes):
|
||||
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc5
|
||||
try:
|
||||
mail_subject = mail_subject.decode()
|
||||
except UnicodeDecodeError:
|
||||
mail_subject = mail_subject.decode('latin-1')
|
||||
if not self.check_contain(mail_subject, self.subject_keyword): #check subject here
|
||||
continue
|
||||
if message.is_multipart():
|
||||
mail_content = ''
|
||||
for part in message.get_payload():
|
||||
flag=False
|
||||
if isinstance(part.get_payload(), list):
|
||||
part = part.get_payload()[0]
|
||||
flag = True
|
||||
if part.get_content_type() in ['text/plain', 'multipart/alternative']:
|
||||
#TODO some string can't be decode
|
||||
if flag:
|
||||
mail_content += str(part.get_payload())
|
||||
else:
|
||||
try:
|
||||
mail_content += base64.b64decode(str(part.get_payload())).decode("utf-8")
|
||||
except UnicodeDecodeError:
|
||||
mail_content += base64.b64decode(str(part.get_payload())).decode('latin-1')
|
||||
else:
|
||||
mail_content = message.get_payload()
|
||||
question['from'] = mail_from
|
||||
question['subject'] = ' '.join(mail_subject.split(' ')[1:])
|
||||
question['content'] = mail_content
|
||||
# print(f'\nFrom: {mail_from}')
|
||||
print(f'\n\nSubject: {mail_subject}')
|
||||
# print(f'Content: {mail_content.replace(" ", "")}')
|
||||
question_list.append(question)
|
||||
question = {'from': None, 'subject': None, 'content': None}
|
||||
imap_server.store(i, "+FLAGS", "\\Deleted") #delete the mail i
|
||||
print("INFO: deleting mail: %s" % mail_subject)
|
||||
imap_server.expunge()
|
||||
imap_server.close()
|
||||
imap_server.logout()
|
||||
return question_list
|
||||
|
||||
def check_contain(self, content, keyword_list):
|
||||
if not keyword_list:
|
||||
return None
|
||||
for ky in keyword_list:
|
||||
if content.find(ky) != -1:
|
||||
return True
|
||||
return None
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ TERMINAL = "terminal"
|
||||
WECHAT = "wechat"
|
||||
WECHAT_MP = "wechat_mp"
|
||||
WECHAT_MP_SERVICE = "wechat_mp_service"
|
||||
GMAIL = "gmail"
|
||||
|
||||
# model
|
||||
OPEN_AI = "openai"
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
"wechat_mp": {
|
||||
"token": "YOUR TOKEN",
|
||||
"port": "8088"
|
||||
},
|
||||
|
||||
"gmail": {
|
||||
"subject_keyword": ["bot", "@bot"],
|
||||
"host_email": "xxxx@gmail.com",
|
||||
"host_password": "GMAIL ACCESS KEY"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user