当前位置: 首页 > news >正文

影刀RPA 邮件附件处理:批量发送与下载

拼多多店群自动化上架方案

影刀RPA 邮件附件处理:批量发送与下载

署名:林焱

什么情况用什么

RPA流程中经常需要处理邮件附件——每天采集的报表自动发送给相关人员;从收件箱下载附件并处理;批量发送不同附件给不同收件人。

场景推荐方式特点
发送带附件邮件smtplib + email标准库,无需安装
下载邮件附件imaplibIMAP协议读取
批量个性化发送smtplib + 模板每人不同附件

怎么做


一:发送带附件的邮件

importsmtplibfromemail.mime.multipartimportMIMEMultipartfromemail.mime.textimportMIMETextfromemail.mime.baseimportMIMEBasefromemailimportencodersimportosdefsend_email_with_attachments(smtp_server,smtp_port,sender_email,sender_password,to_emails,subject,body,attachments=None,is_html=False):"""发送带附件的邮件"""msg=MIMEMultipart()msg["From"]=sender_email msg["To"]=", ".join(to_emails)ifisinstance(to_emails,list)elseto_emails msg["Subject"]=subject# 邮件正文content_type="html"ifis_htmlelse"plain"msg.attach(MIMEText(body,content_type,"utf-8"))# 添加附件ifattachments:forfile_pathinattachments:ifnotos.path.exists(file_path):print(f"附件不存在:{file_path}")continuewithopen(file_path,"rb")asf:part=MIMEBase("application","octet-stream")part.set_payload(f.read())encoders.encode_base64(part)part.add_header("Content-Disposition",f'attachment; filename="{os.path.basename(file_path)}"')msg.attach(part)# 发送try:server=smtplib.SMTP(smtp_server,smtp_port)server.starttls()server.login(sender_email,sender_password)server.sendmail(sender_email,to_emails,msg.as_string())server.quit()print(f"邮件发送成功:{subject}")returnTrueexceptExceptionase:print(f"发送失败:{e}")returnFalse# 使用send_email_with_attachments(smtp_server="smtp.qq.com",smtp_port=587,sender_email="sender@qq.com",sender_password="授权码",# 注意:QQ邮箱用授权码不是密码to_emails=["recipient@example.com"],subject="2024年6月销售报表",body="请查收附件中的月度销售报表。",attachments=[r"D:\报表\6月销售.xlsx",r"D:\报表\6月利润.pdf"])

二:下载邮件附件

importimaplibimportemailimportosfromemail.headerimportdecode_headerdefdownload_attachments(imap_server,email_addr,email_password,folder="INBOX",search_criteria="ALL",save_dir=r"D:\附件",max_emails=50):"""下载邮件附件"""os.makedirs(save_dir,exist_ok=True)# 连接IMAPmail=imaplib.IMAP4_SSL(imap_server)mail.login(email_addr,email_password)mail.select(folder)# 搜索邮件status,messages=mail.search(None,search_criteria)mail_ids=messages[0].split()# 只取最近的N封mail_ids=mail_ids[-max_emails:]iflen(mail_ids)>max_emailselsemail_ids downloaded=[]formail_idinreversed(mail_ids):status,msg_data=mail.fetch(mail_id,"(RFC822)")forresponse_partinmsg_data:ifisinstance(response_part,tuple):msg=email.message_from_bytes(response_part[1])# 获取发件人和主题subject=decode_header_str(msg["Subject"])sender=decode_header_str(msg["From"])# 遍历邮件部分forpartinmsg.walk():content_disposition=str(part.get("Content-Disposition"))if"attachment"incontent_disposition:filename=part.get_filename()iffilename:filename=decode_header_str(filename)# 保存附件filepath=os.path.join(save_dir,filename)# 处理重名base,ext=os.path.splitext(filename)counter=1whileos.path.exists(filepath):filepath=os.path.join(save_dir,f"{base}_{counter}{ext}")counter+=1withopen(filepath,"wb")asf:f.write(part.get_payload(decode=True))downloaded.append({"filename":filename,"path":filepath,"from":sender,"subject":subject})print(f"下载:{filename}(来自:{sender})")mail.logout()returndownloadeddefdecode_header_str(value):"""解码邮件头部字符串"""ifvalueisNone:return""decoded=decode_header(value)result=[]forpart,charsetindecoded:ifisinstance(part,bytes):result.append(part.decode(charsetor"utf-8",errors="replace"))else:result.append(part)return"".join(result)# 使用attachments=download_attachments(imap_server="imap.qq.com",email_addr="receiver@qq.com",email_password="授权码",search_criteria='SUBJECT "报表"',# 只下载标题含"报表"的邮件save_dir=r"D:\附件",max_emails=20)print(f"共下载{len(attachments)}个附件")

三:批量个性化发送

importsmtplibfromemail.mime.multipartimportMIMEMultipartfromemail.mime.textimportMIMETextfromemail.mime.baseimportMIMEBasefromemailimportencodersimportos# yd_input: smtp_config, recipientssmtp_config=yd_input.get("smtp_config",{"server":"smtp.qq.com","port":587,"email":"sender@qq.com","password":"授权码"})recipients=yd_input.get("recipients",[])# recipients格式: [{"email": "a@x.com", "name": "张三", "attachment": "D:\\报表\\张三.xlsx"}, ...]success=0errors=[]forrecipientinrecipients:try:msg=MIMEMultipart()msg["From"]=smtp_config["email"]msg["To"]=recipient["email"]msg["Subject"]=f"{recipient['name']}的月度报表"# 个性化正文body=f"""{recipient['name']},您好: 附件是您的本月数据报表,请查收。 如有疑问请回复此邮件。 此邮件由RPA系统自动发送。 """msg.attach(MIMEText(body,"plain","utf-8"))# 添加附件attachment_path=recipient.get("attachment","")ifattachment_pathandos.path.exists(attachment_path):withopen(attachment_path,"rb")asf:part=MIMEBase("application","octet-stream")part.set_payload(f.read())encoders.encode_base64(part)part.add_header("Content-Disposition",f'attachment; filename="{os.path.basename(attachment_path)}"')msg.attach(part)# 发送server=smtplib.SMTP(smtp_config["server"],smtp_config["port"])server.starttls()server.login(smtp_config["email"],smtp_config["password"])server.sendmail(smtp_config["email"],recipient["email"],msg.as_string())server.quit()success+=1print(f"✓{recipient['name']}<{recipient['email']}>")exceptExceptionase:errors.append(f"{recipient.get('name','unknown')}:{e}")print(f"✗{recipient.get('name','unknown')}:{e}")yd_output={"status":"ok","success":success,"errors":errors,"total":len(recipients)}

有什么坑

坑一:QQ邮箱/网易邮箱登录报认证失败

现象:用邮箱密码登录SMTP/IMAP报Authentication failed

原因:QQ邮箱、网易163邮箱等需要用"授权码"而不是登录密码。

解决:在邮箱设置中开启SMTP/IMAP服务并获取授权码:

# QQ邮箱授权码获取方式:# 1. 登录QQ邮箱网页版# 2. 设置 → 账户 → POP3/IMAP/SMTP服务 → 开启# 3. 按提示用手机发短信获取授权码# 4. 代码中用授权码代替密码# 错误:用QQ登录密码# server.login("sender@qq.com", "qq登录密码") ❌# 正确:用授权码server.login("sender@qq.com","授权码")# ✓# 常见SMTP服务器:# QQ邮箱: smtp.qq.com, 端口587# 163邮箱: smtp.163.com, 端口587# Gmail: smtp.gmail.com, 端口587# Outlook: smtp-mail.outlook.com, 端口587# 企业微信邮箱: smtp.exmail.qq.com, 端口465(SSL)

坑二:中文附件名乱码

现象:附件文件名是中文(如"销售报表.xlsx"),收件人看到的文件名是乱码。

原因:邮件标准对非ASCII文件名的处理方式特殊,需要用RFC 2231编码。

解决

fromemail.utilsimportformataddrfromemail.headerimportHeader# 方案1:用Header编码文件名filename="销售报表.xlsx"encoded_filename=Header(filename,"utf-8").encode()part.add_header("Content-Disposition",f'attachment; filename="{encoded_filename}"')# 方案2:用RFC 2231方式part.add_header("Content-Disposition","attachment",[video(video-B5ZstbUk-1784928796160)(type-csdn)(url-https://live.csdn.net/v/embed/524993)(image-https://v-![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/1b110f986a624baa865330b6cecf452f.png#pic_center)blog.csdnimg.cn/asset/a547123d88ad712dccba346c9217e237/cover/Cover0.jpg)(title-TEMU店群如何管理运营?)]filename=("utf-8","",filename)# 三元组:(编码, 语言, 文件名))# 方案3:同时提供ASCII和UTF-8文件名(兼容性最好)importurllib.parse ascii_name="report.xlsx"# 纯英文备用名part.add_header("Content-Disposition",f'attachment; filename="{ascii_name}"; filename*=UTF-8\'\'{urllib.parse.quote(filename)}')

坑三:附件太大导致发送失败

现象:附件超过20MB,邮件发送失败。

原因:大多数邮箱服务商限制单封邮件大小(通常20-50MB)。

解决:压缩附件或拆分发送:

importzipfileimportosdefcompress_attachments(file_paths,output_zip):"""压缩多个文件为zip"""withzipfile.ZipFile(output_zip,"w",zipfile.ZIP_DEFLATED)aszf:forfile_pathinfile_paths:zf.write(file_path,os.path.basename(file_path))returnoutput_zip# 压缩后发送files=[r"D:\报表\大文件1.xlsx",r"D:\报表\大文件2.xlsx"]zip_path=r"D:\temp\报表压缩包.zip"compress_attachments(files,zip_path)![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/c29927df993c49f2908d91c9b643901a.png#pic_center)# 检查压缩后大小size=os.path.getsize(zip_path)/(1024*1024)# MBifsize>20:print(f"压缩后仍超过20MB ({size:.1f}MB),考虑上传到网盘分享链接")# 上传到网盘,邮件中放链接else:send_email_with_attachments(...,attachments=[zip_path])# 清理临时文件os.remove(zip_path)

坑四:IMAP读取邮件时编码混乱

现象:下载的附件文件名乱码,或邮件主题乱码。

原因:邮件头部的编码方式多样(Base64、Quoted-Printable等),需要正确解码。

解决:用decode_header正确处理:

fromemail.headerimportdecode_headerdefsafe_decode(value):"""安全解码邮件头部"""ifvalueisNone:return""ifisinstance(value,str):# 先尝试直接返回try:parts=decode_header(value)except:returnvalueelse:parts=decode_header(value)result=[]![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/88009f6537724430b98f3f0dd9d415b8.png#pic_center)![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/2983b890ea4c492b8d6e6891761c30a6.png#pic_center)![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b6e0cf39c5024a67af617e91c807d96c.png#pic_center)forpart,charsetinparts:ifisinstance(part,bytes):# 尝试多种编码forencin[charset,"utf-8","gbk","gb2312","latin-1"]:ifenc:try:result.append(part.decode(enc))breakexcept(UnicodeDecodeError,LookupError):continueelse:result.append(part.decode("latin-1",errors="replace"))else:result.append(str(part))return"".join(result)
http://www.jsqmd.com/news/1259330/

相关文章:

  • 神经网络与自适应滑模控制在船舶轨迹跟踪中的应用
  • AI 辅助性能测试——让大模型分析 JFR 文件并给出优化建议
  • 广州新电视塔超高层单元式扭面幕墙的设计应用
  • 企业级智能Agent搭建实战:从架构设计到业务落地
  • 操作系统课程3 - 小镇
  • Linux命令行截图工具Satty的安装与使用指南
  • C++ vector底层源码剖析——从扩容机制到内存优化,面试官到底想问什么?
  • C++日志方案深度对比:printf与spdlog的性能、场景与选型指南
  • 生成式AI在气象预警中的应用与优化实践
  • 可分离架构在物理信息神经网络中的高维PDE求解应用
  • 2026 年新消息:河间正规的电子厂钽废料高价回收店推荐几家,揭秘:电子厂钽废料,如何撬动天价回收市场? - 企业官方推荐【认证】
  • C++手搓JPEG压缩:从原理到实现的图像编码实战
  • 企业级AI Agent平台架构设计:从核心概念到高可用系统实战
  • 2026年最新发布AI获客公司,五家风格各异的专业机构深度解析 - mypinpai
  • UABEAvalonia:跨平台Unity资源编辑器的架构解析与实战应用
  • 测试工程师智能助手:基于NLP的文档问答系统实践
  • 2026 年现阶段靖安有实力的活珠子批发厂家优质厂家找哪家,揭秘!手把手教你如何低价拿下超值活珠子-悠宝活珠子 - 领域鉴赏官
  • AI智能体创造力:随机性与确定性的平衡艺术
  • 《数学三》考研模拟题及解析(五)
  • 虚拟AI产品经理:数据驱动的SaaS需求优先级决策实践
  • 从零搭建C++ OpenCV开发环境:环境配置、核心API与性能优化实战
  • AI如何重塑学术写作:书匠策智能平台实战解析
  • 基于YOLOv8的智能交通车辆测速系统设计与优化
  • C语言入门(1):从源文件到二进制文件-一切始于源代码
  • GPT模型技术演进与多场景应用实践
  • 博士论文写作AI辅助:关键技术与应用实践
  • C++抽象类无法实例化:从编译错误到多态设计的深度解析
  • 2026年莫干山本地运动潮牌,十大品牌真实横评,避坑不交智商税 - mypinpai
  • 深度学习在电力负荷功率分解中的应用与优化
  • Windows 11彻底卸载鲁大师及清除广告弹窗全攻略