Python處理郵件和機器人的實用姿勢

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 沒有看不到的消息,只有不想回的人。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"電子郵件是最古老的互聯網應用之一。在移動互聯網和即時通訊沒爆發前,郵件是人們溝通的主要形式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"和HTTP網頁服務一樣,電子郵件也有自己的協議:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"SMTP"}]},{"type":"text","text":":用來發郵件的協議。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"POP3"}]},{"type":"text","text":":用來收郵件的協議,數據單向從郵箱傳遞給客戶端。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"IMAP"}]},{"type":"text","text":":是"},{"type":"codeinline","content":[{"type":"text","text":"POP3"}]},{"type":"text","text":"的擴展,可以瀏覽摘要後再選擇下載郵件,也可以從本地同步數據給郵箱。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Python提供了4個標準模塊處理郵件:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"smtplib"}]},{"type":"text","text":",用於發郵件。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"poplib"}]},{"type":"text","text":",用"},{"type":"codeinline","content":[{"type":"text","text":"POP3"}]},{"type":"text","text":"協議收郵件。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"imaplib"}]},{"type":"text","text":",用"},{"type":"codeinline","content":[{"type":"text","text":"IMAP"}]},{"type":"text","text":"協議同步客戶端和郵箱數據。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"email"}]},{"type":"text","text":",用於解析郵件內容結構。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"20年前,只要你能連到互聯網,就能提供郵箱服務。那時候的互聯網,除了門戶網站,就是電子郵件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隨着准入門檻的提高,目前郵箱服務主要由電信運營商和幾個互聯網巨頭提供,以Web版和App客戶端爲主,一般都需要獨立授權碼才能開啓三方客戶端訪問其"},{"type":"codeinline","content":[{"type":"text","text":"SMTP/IMAP/POP3"}]},{"type":"text","text":"接口。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8d/8d7d4e984a3404c0028f8bcbb3371bdd.png","alt":"image-20200820001117135","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d5/d53d7eaf8237891f7c3198a508b9d245.png","alt":"image-20200820093416547","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"郵件主要的2個用途:正式溝通、自動通知。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "},{"type":"text","marks":[{"type":"strong"}],"text":"“正式溝通”"},{"type":"text","text":"指較爲正式的事項確認,工作中較常見。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "},{"type":"text","marks":[{"type":"strong"}],"text":"“自動通知”"},{"type":"text","text":"指主動發送或者當條件出發時自動發送郵件。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“自動通知”的應用範圍較廣,如訂閱頻道後定期推送內容,代碼構建失敗後通知成員,每日收集情報後彙總發送給有關人員等等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隨着互聯網辦公軟件成熟,羣組功能在企業內應用也更加廣泛,企業微信和釘釘是國內2個最主流的企業辦公服務軟件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"它們都提供了機器人功能,可以自動通知消息到所在羣組成員,比郵件及時,也更靈活。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/29/29113960367efa486fc3f9c43b7cf192.png","alt":"image-20200821095423135","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以我們可以把這類應用歸爲自動通知場景:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"自動發送郵件:如定時週報或條件觸發後自動郵件通知。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"歸檔整理郵件:自動下載郵件,提取內容保存,如附件。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"機器人通知:釘釘和企業微信羣內自動通知相關成員。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"發送郵件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用Python發郵件主要分3步:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"構造郵件內容"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"賬號登陸授權"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"發送郵件消息"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中有幾個注意點:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"登陸密碼是授權碼,而非郵箱Web版客戶端的登陸密碼。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有些服務商會選用自定義端口並要求用SSL加密後發郵件。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不同服務商在協議實現支持上可能會有不同,有些服務商會禁止通過協議訪問郵箱數據。此外用非官方客戶端訪問時,會出現'system busy'等提示,估計資源分配不如官方版本。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"真正發送者和目標在"},{"type":"codeinline","content":[{"type":"text","text":"sendmail()"}]},{"type":"text","text":"方法中指定,郵件中的"},{"type":"codeinline","content":[{"type":"text","text":"From"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"To"}]},{"type":"text","text":"只是內容一部分。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"尤其是最後一點,早先成了不少電子郵件欺詐者的幫兇,理論上的“發件人”你可以寫任何名字。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如下面標示的郵箱地址都是“假的”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/83/8371781a1ce645cd8ec0516db2136345.png","alt":"image-20200820004725145","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前一些服務商會對郵件內容做敏感信息過濾。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"發送純文本郵件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"# 純文本郵件\nimport smtplib\nfrom email.mime.text import MIMEText\n# 構造郵件\nmsg = MIMEText('Hello Python1024!', 'plain', 'utf-8')\nmsg['From'] = '程一初 '\nmsg['To'] = '程一初1 , 程一初2 '\nmsg['Subject'] = '來自Python1024'\nfrom_addr = '[email protected]'\n# 密碼是授權碼\npassword = ''\nto_addr = '[email protected]'\nsmtp_server = 'smtp.qq.com'\n# QQ郵箱的SMTP服務需SSL加密,端口爲465\nserver = smtplib.SMTP_SSL(smtp_server)\n# 顯示發送過程\nserver.set_debuglevel(1)\n# 登陸驗證\nserver.login(from_addr, password)\n# 發送郵件\nserver.sendmail(from_addr, [to_addr], msg.as_string())\n# 退出\nserver.quit()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"發送HTML郵件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"import smtplib\nfrom email.mime.text import MIMEText\n# 構造郵件\nmsg = MIMEText('

Python1024

' +\n '

程一初 發送。

', 'html', 'utf-8')\nmsg['From'] = '程一初 '\nmsg['To'] = '程一初1 , 程一初2 '\nmsg['Subject'] = '來自Python1024'\nfrom_addr = '[email protected]'\n# 密碼是授權碼\npassword = ''\nto_addr = '[email protected]'\nsmtp_server = 'smtp.qq.com'\nserver = smtplib.SMTP_SSL(smtp_server, 465)\nserver.login(from_addr, password)\nserver.sendmail(from_addr, [to_addr], msg.as_string())\nserver.quit()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"發送帶附件郵件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"import pathlib\nimport smtplib\nfrom email.mime.text import MIMEText\nfrom email.mime.multipart import MIMEMultipart\nfrom email.mime.image import MIMEImage\nfrom email.mime.application import MIMEApplication\npath = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/009email')\nfile_path = path.joinpath('avatar.jpg')\nzip_path = path.joinpath('avatar.jpg.zip')\n# 構造郵件\nmsg = MIMEMultipart()\nmsg['From'] = '程一初 '\nmsg['To'] = '程一初1 , 程一初2 '\nmsg['Subject'] = '來自Python1024'\nfrom_addr = '[email protected]'\nmsg.attach(MIMEText('請查收附件', 'html', 'utf-8'))\n# 圖像文件在郵箱Web客戶端中可以預覽\nwith open(file_path, 'rb') as f:\n mime = MIMEImage(f.read())\n mime.add_header('Content-Disposition', 'attachment',\n filename=file_path.name)\n mime.add_header('Content-ID', '')\n msg.attach(mime)\n# 其他應用文件\nwith open(zip_path, 'rb') as f:\n mime = MIMEApplication(f.read())\n mime.add_header('Content-Disposition', 'attachment',\n filename=zip_path.name)\n msg.attach(mime)\npassword = ''\nto_addr = '[email protected]'\nsmtp_server = 'smtp.qq.com'\nserver = smtplib.SMTP_SSL(smtp_server, 465)\nserver.login(from_addr, password)\nserver.sendmail(from_addr, [to_addr], msg.as_string())\nserver.quit()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"收郵件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Python收郵件可以選擇使用"},{"type":"codeinline","content":[{"type":"text","text":"POP3"}]},{"type":"text","text":"或"},{"type":"codeinline","content":[{"type":"text","text":"IMAP"}]},{"type":"text","text":"兩種協議。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"poplib"}]},{"type":"text","text":":用"},{"type":"codeinline","content":[{"type":"text","text":"POP3"}]},{"type":"text","text":"協議收取MIME內容。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"smtplib"}]},{"type":"text","text":":用"},{"type":"codeinline","content":[{"type":"text","text":"IMAP"}]},{"type":"text","text":"獲取郵箱內容,也可以同步數據給郵箱,數據可以雙向傳遞。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從郵箱收到數據後,可以用"},{"type":"codeinline","content":[{"type":"text","text":"email"}]},{"type":"text","text":"模塊按郵件標準格式解析。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"用"},{"type":"codeinline","content":[{"type":"text","text":"POP3"}]},{"type":"text","text":"自動下載郵件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"import pathlib\nimport poplib\nfrom email.parser import Parser\nfrom email.header import Header, decode_header\npath = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/009email')\nout_path = path.joinpath('009email_pop3')\n\ndef download_msg(msg, idx, path=out_path):\n \"\"\"解析郵件並保存到文件\"\"\"\n for part in msg.walk():\n # 遍歷郵件內容\n if not part.is_multipart():\n # 有文件名即爲附件\n filename = part.get_filename()\n # 獲取內容並解碼\n content = part.get_payload(decode=True)\n if filename:\n # 獲取信息頭中文件名\n h = decode_header(Header(filename))\n filename = str(h[0][0], encoding='utf-8')\n file_path = path.joinpath(f'mail_{idx}_attach_{filename}')\n else:\n file_path = path.joinpath(f'mail_{idx}_text')\n with open(path.joinpath(file_path), 'wb') as f:\n f.write(content)\n\nuser = '[email protected]'\npassword = ''\npop3_svr = 'pop.qq.com'\nsvr = poplib.POP3_SSL(pop3_svr)\nsvr.set_debuglevel(1)\nprint(svr.getwelcome().decode('utf-8'))\n# 認證登陸\nsvr.user(user)\nsvr.pass_(password)\n# 查看郵箱內郵件數、佔用空間\nprint('郵件 {} 封, 佔用 {} 字節。'.format(*svr.stat()))\n# 郵件列表\nresp, mails, octets = svr.list()\nprint(mails)\n# 獲取最新郵件, 注意索引從1開始\nindex = len(mails)\nresp, lines, octets = svr.retr(index)\n# 獲取的郵件內容按行合併\nmsg_content = b'\\r\\n'.join(lines).decode('utf-8')\n# 獲取MIME對象\nmsg = Parser().parsestr(msg_content)\n# 下載郵件內容\ndownload_msg(msg, index)\nsvr.quit()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"用"},{"type":"codeinline","content":[{"type":"text","text":"IMAP"}]},{"type":"text","text":"自動下載郵件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"import re\nimport pathlib\nimport imaplib\nimport email\nfrom email.parser import BytesFeedParser\nfrom email.header import Header, decode_header, make_header\n\npath = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/009email')\nout_path = path.joinpath('009email_imap')\n\ndef download_msg(msg, idx, path=out_path):\n # \n pass\n\nuser = '[email protected]'\npassword = ''\nimap_svr = 'imap.qq.com'\nimaplib.Debug = 4\nsvr = imaplib.IMAP4_SSL(imap_svr)\nsvr.login(user, password)\nprint(svr.welcome)\n# 列出所有郵箱\nrcode, mbox_list = svr.list()\n# 用正則表達式解析信息\nlist_pattern = re.compile(r'.(?P.*?). \"(?P.*)\" (?P.*)')\nfor mbox in mbox_list:\n flags, delimiter, mbox_name = list_pattern.match(mbox.decode('utf-8')).groups()\n print(mbox_name.strip())\n# 檢查某個郵箱狀態,如郵件數、未讀郵件等\nrcode, res = svr.status('INBOX','(MESSAGES RECENT UNSEEN)',)\nprint(res)\n# 選擇一個郵箱\nrcode, res = svr.select('INBOX', readonly=True)\nprint(f'共有 {int(res[0])} 封郵件')\n# 查詢未讀郵件,返回郵件ID\nrcode, msg_ids = svr.search('(UNSEEN)')\nprint(msg_ids)\n# QQMail的IMAP不支持按主題搜索,搜索功能有限\nrcode, msg_ids = svr.search('(SUBJECT \"python1024\")',)\nprint(rcode, msg_ids)\nfor m in msg_ids[0].split():\n # 根據郵件ID獲取郵件,按RFC822格式\n rcode, msg_data = svr.fetch(m, '(RFC822)')\n for part in msg_data:\n if isinstance(part, tuple):\n msg = email.message_from_bytes(part[1])\n download_msg(msg, str(m, encoding='utf-8'), out_path)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"用"},{"type":"codeinline","content":[{"type":"text","text":"IMAP"}]},{"type":"text","text":"協議同步信息到郵箱"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"import time\nimport imaplib\nfrom email.message import Message\n\nuser = '[email protected]'\npassword = ''\nimap_svr = 'imap.qq.com'\nimaplib.Debug = 4\nsvr = imaplib.IMAP4_SSL(imap_svr)\nsvr.login(user, password)\n# 創建一個郵箱\nrcode, res = svr.create('python1024')\nprint(rcode, res)\n# 構造一條郵件信息\nmsg = Message()\nmsg.set_unixfrom('pymotw')\nmsg['Subject'] = 'Python1024上傳主題'\nmsg['From'] = '[email protected]'\nmsg['To'] = '[email protected]'\nmsg.set_payload('這是Python1024上傳的信息')\n# 上傳信息\nsvr.append('python1024', '',\n imaplib.Time2Internaldate(time.time()),\n str(msg).encode('utf-8'))\nrcode, res = svr.select('python1024')\nprint(f'有{res[0]}封郵件。')\nrcode, res = svr.search('ALL')\nmsg_id = res[0].split()[-1]\n# 設置新信息未讀狀態\nsvr.store(msg_id, '-FLAGS', '(\\Seen)')\nrcode, res = svr.fetch(msg_id, '(FLAGS)')\nprint(res)\n# 可以把消息複製到其他郵箱\nsvr.copy(msg_id, 'INBOX')"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"機器人應用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏所謂的機器人,是指釘釘、企業微信中參與聊天的機器人賬號。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其本質是一個"},{"type":"codeinline","content":[{"type":"text","text":"restful"}]},{"type":"text","text":"接口的賬號,通過接口控制賬號行爲。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前這類機器人主要應用場景有:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"快速傳達信息到社羣內,如技術運維、運營分析、情報獲取等信息。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"打造自動社羣體驗流程,如自助客服、新業務體驗等。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在釘釘和企業微信中,一般由管理員創建機器人:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"釘釘羣和企業微信內部羣支持機器人主動發送信息。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"企業微信外部羣機器人只能被動迴應關鍵詞,不能主動發信息。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面主要介紹釘釘和企業微信內部羣的機器人使用方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"創建機器人流程:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"創建釘釘/企業微信內部羣。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"在羣設置中,添加機器人。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"記錄下調用機器人的web地址。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"調用機器人的接口需要發送HTTP請求,常用的Python模塊如"},{"type":"codeinline","content":[{"type":"text","text":"urllib"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"requests"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"requests"}]},{"type":"text","text":"模塊安裝:"},{"type":"codeinline","content":[{"type":"text","text":"pip install requests"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"發送消息流程就2步:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"構建消息內容數據"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"使用"},{"type":"codeinline","content":[{"type":"text","text":"requests"}]},{"type":"text","text":"發送"},{"type":"codeinline","content":[{"type":"text","text":"post"}]},{"type":"text","text":"請求。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意點:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲HTTP請求增加頭部信息,指明請求內容爲"},{"type":"codeinline","content":[{"type":"text","text":"json"}]},{"type":"text","text":"數據。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提交請求時,需要用"},{"type":"codeinline","content":[{"type":"text","text":"json.dumps()"}]},{"type":"text","text":"方法對數據編碼。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"機器人發送消息有頻率限制:20條/分鐘"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"釘釘機器人使用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"import json\nimport requests\n\ntoken = ''\nkeyword = 'python1024'\nrobot_url = f'https://oapi.dingtalk.com/robot/send?access_token={token}'\nHEADERS = {'Content-Type': 'application/json'}\n# 發送文本消息\ntxt_msg = {\n 'msgtype': 'text', \n 'text': {\n 'content': '歡迎加入Python1024學習羣。'\n }, \n 'at': {\n 'atMobiles': [\n '138xxxxxxxx',\n ], \n \"isAtAll\": True\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(txt_msg))\nprint(r.json())\n# 發送鏈接信息\nlink_msg = {\n 'msgtype': 'link',\n 'link': {\n 'text': '歡迎加入Python1024,一起探索效率提升。',\n 'title': '程一初的語雀空間',\n 'picUrl': 'https://cdn.nlark.com/yuque/0/2019/png/265643/1550131528833-avatar/b9063fa5-24b2-4360-aaae-8374fa12c8aa.png',\n 'messageUrl': 'https://www.yuque.com/yichu/'\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(link_msg))\nprint(r.json())\n# 發送Markdown消息\nmd_msg = {\n 'msgtype': 'markdown',\n 'markdown': {\n 'title': '歡迎加入Python1024',\n 'text': '![animate](https://picbed-yichu.oss-cn-shenzhen.aliyuncs.com/picgo/58932a984729f.gif) [視頻處理的實用工具](https://www.yuque.com/yichu/selflearning/as6xzv)'\n },\n 'at': {\n \"isAtAll\": True\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(md_msg))\nprint(r.json())\n# 卡片消息\ncard_msg = {\n 'msgtype': 'actionCard',\n 'actionCard': {\n 'title': '歡迎加入Python1024',\n 'text': '![animate](https://picbed-yichu.oss-cn-shenzhen.aliyuncs.com/picgo/58932a984729f.gif) [視頻處理的實用工具](https://www.yuque.com/yichu/selflearning/as6xzv)',\n 'btnOrientation': '0', \n 'singleTitle': '打開空間',\n 'singleURL': 'https://www.yuque.com/yichu/'\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(card_msg))\nprint(r.json())\n# 選項卡片消息\ncardm_msg = {\n 'msgtype': 'actionCard',\n 'actionCard': {\n 'title': '歡迎加入Python1024',\n 'text': '![animate](https://picbed-yichu.oss-cn-shenzhen.aliyuncs.com/picgo/58932a984729f.gif) [視頻處理的實用工具](https://www.yuque.com/yichu/selflearning/as6xzv)',\n 'btnOrientation': '0', \n 'btns': [\n {\n 'title': 'Python自學手冊', \n 'actionURL': 'https://www.yuque.com/yichu/selflearning/ux59c6'\n }, \n {\n 'title': 'Python自動辦公', \n 'actionURL': 'https://www.yuque.com/yichu/'\n }\n ]\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(cardm_msg))\nprint(r.json())\n# 發送信息流卡片消息\nfree_card_msg = {\n 'msgtype': 'feedCard',\n 'feedCard': {\n 'links': [\n {\n 'title': '程一初的語雀空間',\n 'messageURL': 'https://www.yuque.com/yichu/',\n 'picURL': 'https://cdn.nlark.com/yuque/0/2019/png/265643/1550131528833-avatar/b9063fa5-24b2-4360-aaae-8374fa12c8aa.png'\n },\n {\n 'title': 'Python1024自動辦公系列',\n 'messageURL': 'https://www.yuque.com/yichu/selflearning/ux59c6',\n 'picURL': 'https://cdn.nlark.com/yuque/0/2020/png/265643/1597933041598-ccd75182-aa75-447c-a1f5-7a2685acf88d.png'\n }\n ]\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(free_card_msg))\nprint(r.json())"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"企業微信內部羣機器人使用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"import base64\nimport hashlib\nimport pathlib\nimport json\nimport requests\n\npath = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/009email')\nfile_path = path.joinpath('avatar.jpg.zip')\nimg_path = path.joinpath('avatar.jpg')\ntoken = ''\nrobot_url = f'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={token}'\nHEADERS = {'Content-Type': 'application/json'}\n# 發送文本消息\ntxt_msg = {\n 'msgtype': 'text', \n 'text': {\n 'content': '歡迎加入Python1024學習羣。',\n 'mentioned_list':['ichengplus6','@all'],\n 'mentioned_mobile_list': ['138XXXXXXX']\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(txt_msg))\nprint(r.json())\n# 發送Markdown消息\nmd_msg = {\n 'msgtype': 'markdown',\n 'markdown': {\n 'content': '1.[Python基礎系列](http://mp.weixin.qq.com/mp/homepage?__biz=MzUxNzE4MDkzNw==&hid=2&sn=7d05116c613d0e41797858d59d61ffb2&scene=18#wechat_redirect)\\n\\\n 2.[Python自動辦公系列](https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1477393309697392646&__biz=MzUxNzE4MDkzNw==#wechat_redirect)'\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(md_msg))\nprint(r.json())\n# 發送圖片消息,編碼前不超過2M,JPG、PNG\nwith open(img_path, 'rb') as f:\n img_data = f.read()\nb64img = base64.b64encode(img_data)\nmd5 = hashlib.md5()\nmd5.update(img_data)\nimg_msg = {\n 'msgtype': 'image',\n 'image': {\n 'base64': b64img.decode('utf-8'),\n 'md5': md5.hexdigest()\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(img_msg))\nprint(r.json())\n# 發送圖文消息\nnews_msg = {\n 'msgtype': 'news',\n 'news': {\n 'articles': [\n {\n 'title':'Python基礎系列',\n 'description': '通往高手的必經之路,看得懂、學得會、用得上。',\n 'url': 'http://mp.weixin.qq.com/mp/homepage?__biz=MzUxNzE4MDkzNw==&hid=2&sn=7d05116c613d0e41797858d59d61ffb2&scene=18#wechat_redirect',\n 'picurl': 'http://mmbiz.qpic.cn/mmbiz_jpg/kSfot6Ez8OicVK0w0bwOkUjYG7I3Sux1icQjjKO7PPMud4YtqoU767mYcrRZNyOicHJiaEFfAGvcz1GWkYWxHxmPpA/0'\n },\n {\n 'title':'Python自動辦公系列',\n 'description': '涵蓋文本、Word、PPT、Excel、圖像、音頻、視頻、郵件、機器人等常見應用。',\n 'url': 'https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1477393309697392646&__biz=MzUxNzE4MDkzNw==#wechat_redirect',\n 'picurl': 'http://mmbiz.qpic.cn/mmbiz_jpg/kSfot6Ez8O9sMTzMoHTiaTONYfwAO4ibFc7KaIyMM1xedibr2PHs2e9MD9SuS22v3nZL5b80dd3Ynarkm0fibbEuZA/0'\n }\n ]\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(news_msg))\nprint(r.json())\n# 發送文件\nmedia_id = ''\nif not media_id:\n # 上傳文件\n url = f'https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key={token}&type=file'\n files = [('file', (file_path.name, open(file_path, 'rb')))]\n r = requests.post(url, files=files)\n j = r.json()\n media_id = j['media_id']\nprint(media_id)\nfile_msg = {\n 'msgtype': 'file',\n 'file': {\n 'media_id': media_id\n }\n}\nr = requests.post(robot_url, headers=HEADERS, data=json.dumps(file_msg))\nprint(r.json())"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文主要介紹了用Python收發郵件的主要場景,以及釘釘和企業微信機器人的基本使用方法。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在現實的互聯網運營中,我們經常會發現一些非官方支持的機器人,如微信機器人、QQ機器人等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些都是通過破解官方客戶端協議實現,屬於非正常使用,受到官方打擊和封禁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"哪裏有流量紅利,哪裏就會有更多技術創新,雖然有時創新的技術非官方所願。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前,釘釘的功能更豐富,但企業微信背靠10億級月活的微信,也正在發力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你認爲哪個更有潛力呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"歡迎入羣交流,前100名免費。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9c/9c91bab30b2c905274cd45c27d02c27c.png","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章