尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ModuleNotFoundError: No module named ‘yagmail‘ 排查与解决全攻略

ModuleNotFoundError: No module named ‘yagmail‘ 排查与解决全攻略 1. ModuleNotFoundError: No module named yagmail 到底在告诉你什么1.1 这是Python最诚实的一类报错如果你在脚本第一行写了import yagmail然后运行终端却甩回一行红色日志ModuleNotFoundError: No module named yagmail别急着怀疑人生这一行信息量其实非常大。它的直译是Python解释器在当前环境中按照它自己的模块搜索路径也就是sys.path找了半天没有找到名字叫yagmail的包。注意这不属于语法错误也不属于逻辑错误而是导入期错误。Python先把你的代码做语法分析没问题之后开始逐行执行等真正跑到import yagmail这句话时才会去sys.path里列出的所有目录里找包。全部找完还是没有于是抛出一个ModuleNotFoundError。用生活化的话说就像你去厨房做菜菜谱第一步写着“拿出生抽”你打开调料柜、台面、冰箱都翻了一遍结果没有于是你跟家里人喊了一嗓子“家里没有生抽”。Python就是这个“喊话”机制它只会按固定目录列表找不会自己跑到硬盘每个角落去全局搜索。所以当你看到这种报错第一反应应该是不是脚本内容有问题而是运行环境里少了东西或者运行环境和我以为的环境不是同一个。1.2 No module named 和 ImportError 不是一回事很多在早期Python版本里折腾过的朋友可能记得以前 import 失败统一报ImportError没有ModuleNotFoundError这一说。后来 Python 3.6 把“模块不存在”单独拆成了ModuleNotFoundError并且让它成为ImportError的子类。这意味着两件事第一如果你以前见过ImportError: No module named yagmail那和现在看到的ModuleNotFoundError: No module named yagmail本质上是同一个问题只是版本不一样Python的报错分类更细分了。第二有些老代码为了兼容会用except ImportError去捕获导入异常这依然能捕获到ModuleNotFoundError因为子类会被父类异常捕获。但在排查Bug时看到ModuleNotFoundError要更聚焦它明确告诉你“这个包根本不存在”而不是“这个包存在但内部某一步导错了”那是另一个报错方向。从实操角度讲遇到No module named yagmail默认先判定“没装”但紧接着要意识到一个更扎心的问题装了也可能找不到。因为这里有“环境”两个字在中间作梗。这也就是为什么会出现“我明明pip install了为什么还是报错”这种让人抓狂的情况。2. 为什么你已经 pip install 了程序还是找不到2.1 虚拟环境和全局环境的错位新手最容易掉进去的坑就是环境错位。我给你描述一个极其常见的操作路径你在 PyCharm 里新建了一个项目PyCharm 默认会自动创建venv虚拟环境。好项目右边的终端里pip install yagmail执行成功没有报错。接着你开心地去系统桌面打开 cmd 或者 Windows Terminal在另一个目录运行python test.py结果弹出ModuleNotFoundError: No module named yagmail。问题出在哪PyCharm 的项目终端里默认已经把虚拟环境激活了你安装yagmail是装进了venv的site-packages。但你在系统终端里运行的python是全局的 Python 解释器。全局环境的第三方包目录里没有yagmail自然而然就报错了。所以在排查之前你要先分清“代码是在哪个环境运行的”。想验证当前 Python 到底是哪一套可以运行python -c import sys; print(sys.executable)如果在虚拟环境里打印出来的路径会指向项目目录下的venv/bin/pythonWindows 下是venv\Scripts\python.exe。如果执行结果指向/usr/bin/python或者某个不知名路径那就说明你根本没在项目环境里跑脚本。我见过太多人删了好几次包、重装好几遍yagmail还是报错最后发现只是终端窗口用错了。建议是以后跑 Python 脚本尽量从同一套集成开发环境的终端窗口去跑比如 PyCharm 的项目终端、VS Code 的集成终端因为这些终端通常会帮你自动激活已选中的环境。不建议开一个独立的系统 cmd 去跑工程里的脚本那不是不行而是你很容易忘记激活环境。2.2 pip 和 python 可能根本不是同一套工具第二个高频原因是pip对应的 Python 环境和你的python命令对应的 Python 环境不是同一个。现在很多电脑里同时装了好几个 Python官方 python.org 的安装包、Anaconda、MiniConda、Windows Store 里装的 Python、还有各种 IDE 自带的 Python。它们各自有独立的site-packages目录。如果某个程序在 PATH 里抢占了先机你在命令行敲pip时它指向的可能是一套环境敲python时它又指向了另一套环境。解决方案极其简单但极其重要不要使用裸的pip命令改用python -m pip方式。python -m pip install yagmail这条命令的意思是把pip当作python这个解释器的一个模块来运行这样就保证了 pip 一定跟随当前这个 python 走装进当前这个 python 对应的site-packages。只要运行脚本时用的也是同一个python就不会发生“装到 A 环境、跑在 B 环境”的诡异事件。这条经验不只是针对yagmail。你以后遇到No module named numpy、No module named opencv、No module named pkg_resources甚至No module named pip排查第一步永远是问自己当前正在运行的 Python 到底是哪一套包又装到哪一套去了把这两个问题弄清楚至少能解决一半以上的导入类报错。2.3 系统Python保护机制externally-managed-environment近几年在 Debian、Ubuntu 等 Linux 发行版上直接给系统 Pythonpip install经常会看到这样的报错error: externally-managed-environment标题相关热词里出现的pip install modelscope error: externally-managed-environment就是这个问题。很多人第一次见到这个错误以为电脑坏了其实不是。这是系统在保护自己背后是 PEP 668 规范。系统 Python 的第三方包主要由apt包管理器来维护如果你拿pip乱装一通很容易覆盖系统关键依赖甚至把整个python3环境搞崩。遇到这种报错我最推荐的做法是在项目目录下创建一个虚拟环境在venv里安装不要强行和系统环境对着干。如果只是临时验证一个小模块也可以使用--break-system-packages参数强制安装但我不建议把这个养成长期习惯。你要是后面发现了依赖冲突会非常痛苦。3. 一步步把 yagmail 装进正确的环境3.1 安装前先做一次环境体检不要一上来就复制粘贴pip install yagmail我先建议你花 20 秒做环境体检。按顺序执行下面几条命令python --version python -m pip --version python -m pip show yagmail第一条看 Python 版本第三条看当前环境里是否已经存在yagmail。如果最后一条命令输出了Name: yagmail、Version: 0.6.3、Location: ...这样的信息说明当前这个 Python 环境里早就装好了那你应该回头检查之前脚本运行用的到底是哪个环境。如果pip show没有输出任何信息只是安静地回到命令提示符就说明确实没有安装。如果你创建了虚拟环境但还没激活Windows 下用venv\Scripts\activateLinux 和 macOS 下用source venv/bin/activate激活后命令行的最前面一般会出现括号里写着venv的提示符。这一步做好之后再继续安装。3.2 安装命令与镜像源选择最基础、最稳的安装命令是python -m pip install yagmail如果你在国内的网络环境里安装可能会遇到下载慢、连接超时、卡在进度条上不动的情况。这时候可以把包源切换到清华镜像python -m pip install yagmail -i https://pypi.tuna.tsinghua.edu.cn/simple这个-i参数的意思是--index-url也就是临时指定本次安装使用的 PyPI 镜像源。镜像源的原理很简单它相当于把 PyPI 官方仓库在海外服务器上的包同步了一份放在国内访问速度会明显更快。需要注意的是镜像源站的同步会有短暂延迟极少情况下会碰到某个包的最新版还没同步过来这时把版本调低一级或者用官方源再试一次就好。如果你不是在一个全新的虚拟环境里安装而是直接对系统 Python 操作还可能会看到这么一行提示Defaulting to user installation because normal site-packages is not writeable翻译一下就是当前site-packages目录不可写pip 决定把包装到当前用户目录下。这种情况通常出现在 macOS 和 Linux 上。你确实可以接着用但我还是会建议优先进入一个虚拟环境再装省得后续权限问题反复出现。3.3 安装后真的要验证一次很多人在终端看到Successfully installed yagmail-0.6.3就以为万事大吉了转头运行脚本又报错。为什么因为pip install成功只能说明包装进了当前pip对应的环境但不代表你运行脚本时使用的解释器环境一定就是刚才那个。所以安装完成之后我建议在同一个终端里运行一次动态导入python -c import yagmail; print(yagmail.__version__)如果成功打印出版本号比如0.6.3那就说明当前这个终端环境里真正可以用yagmail了。只要后续你始终用同一个环境去跑脚本就不会再看到No module named yagmail。记住一个原则pip show验证的是安装元数据import验证的是真实的运行时环境。把两条命令都在同一个终端里跑一遍两者一致才算彻底闭合。4. 安装过程中那些反复把人劝退的问题4.1 老被提示 pip 版本太旧很多朋友在安装任何包之前都会看到一行警告WARNING: You are using pip version 21.1.1; however, version 25.0.1 is available.这种提示看着很烦但说实话老版本的 pip 去安装yagmail这种小包大概率也能成功。可如果一直拖延不升级遇到某些依赖解析复杂的包、或者对新版 wheel 二进制包支持不佳的包时就容易卡住而且报错信息还很难读懂。我的习惯是在新建虚拟环境并激活之后第一件事先升级 pippython -m pip install --upgrade pip等pip版本升上去以后再去install yagmail。你会发现后续的依赖解析更快关于externally-managed-environment之类的提示也会更准确。升级完 pip 后再顺手看看镜像源如果之前装的时候用的是默认源升级也会更快。4.2 网络超时、ReadTimeoutError、连接被重置在终端里遇到ReadTimeoutError或者Connection reset by peer之类的报错是网络原因不是命令写错了。默认情况下pip 会从官方 PyPI 下载包如果你的网络和官方源之间的连接不稳定下载容易中断。做法有三步一是加超时时间和重试次数python -m pip install yagmail --timeout 60 --retries 5二是直接用国内镜像源前面已经说过用-i参数临时指定即可。三是如果每次都很慢可以设置全局默认镜像源一劳永逸python -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple设置完之后默认的 pip 下载行为就都走镜像源了。值得注意的是如果你在公司内网某些镜像站可能访问不了这时优先用内网自建的 PyPI 镜像而不是硬套公共镜像地址。4.3 依赖冲突和全局环境“大杂烩”yagmail 本身依赖很少通常只有python-dateutil之类的轻量库所以单独安装它时几乎遇不到依赖冲突。但如果你把所有 Python 包都塞进同一个全局环境时间久了就会出问题。比如foo包依赖旧版urllib3bar包依赖新版urllib3两个包装在一起pip 在解析依赖时可能直接报出让你看不懂的“Dependency conflict”错误。这就要回到前面反复强调的虚拟环境。每一个项目都应该有自己独立的虚拟环境而不是一个环境里住满了所有项目的地盘。这就像你不会让十个家庭共用一间厨房一样各种调料和生活习惯混在一起迟早会打起来。实际工作中我见过为了解一个依赖冲突查了三天的人最后发现把项目单独venv一下问题在十分钟之内就解决掉了。4.4 总觉得要 sudo 才能装用sudo pip install是很多人踩过的最大的坑。你可能觉得系统提示Permission denied那就加sudo好了。但在 Linux 系统里sudo pip install会把包直接写进系统级 Python 的site-packages一旦装错版本或卸载不当很容易把系统依赖搞乱。更麻烦的是sudo安装的包权限属于 root你以后的普通用户进程想删都删不掉。正确的解法是如果你只是自己开发用就创建虚拟环境不需要 root 权限也不会弄脏系统。如果非要为系统 Python 装包用python -m pip install --user yagmail安装到用户目录避免动系统全局目录。把“少用 sudo 装 Python 包”这条刻进脑子里可以帮你避开无数麻烦。5. yagmail 到底能干什么以及真实使用体验5.1 一个最小可用的发邮件脚本在解决完环境问题之后也许你会好奇yagmail这个包到底解决什么问题。简单说它是一个用来“让 Python 发送邮件变得非常简单”的库。如果用 Python 标准库smtplib去发邮件你需要手动处理 SMTP 连接、登录、构造邮件头、构造 MIME 文本、加附件等一堆操作少说也要几十行代码。而yagmail把大部分细节都包掉了代码可以少到一个令人惊讶的程度import yagmail yag yagmail.SMTP(useryougmail.com, passwordyour_app_password) yag.send( toreceiverexample.com, subject测试邮件, contents这是用 yagmail 发送的正文内容。 )就这么几行一封邮件就发出去了。这就是yagmail存在的意义明明一个自动化任务只需要很小的代码量你没必要为了它手写太复杂的底层逻辑。对于跑数据定时报表、发监控告警、给用户批量发通知这类脚本来说它的简洁性非常有吸引力。5.2 使用中需要注意的细节第一个要注意的是密码问题。上面示例代码里的明文密码我个人不推荐直接写死在脚本里尤其当脚本要提交到 git 仓库时。至少也要从环境变量里读取或者使用邮箱服务商提供的“应用专用密码”。像 Gmail 这类邮箱开启两步验证之后可以为某个应用单独生成一个随机密码比主密码安全得多。第二个细节是自定义 SMTP 服务器。默认情况下yagmail会根据你传入的邮箱后缀自动推断 SMTP 服务器比如 Gmail 就自动去smtp.gmail.com。如果你用的是公司企业邮箱后缀可能比较小众自动推断会失败这时需要显式传入host参数yag yagmail.SMTP(useryoucompany.com, passwordyour_password, hostsmtp.company.com)第三个细节是附件路径。写contents[附件文件.pdf]时如果使用相对路径脚本执行时的工作目录必须和文件实际路径一致。为了减少不确定性尽量用绝对路径或者先通过os.path.abspath把相对路径转成绝对路径。第四个细节是关于送达率的现实认识。脚本显示发送成功只代表 SMTP 服务端接收了这个邮件请求不代表收件方一定会把它放进收件箱。你的发信域名如果缺少 SPF、DKIM 等设置或者服务器 IP 信誉不好邮件很容易进垃圾箱。这是任何邮件自动化脚本都无法完全绕开的现实问题。6. 以后遇到 ModuleNotFoundError可以直接查这张表6.1 报错现象与排查操作对照报错现象可能原因推荐操作ModuleNotFoundError: No module named yagmail当前环境没有安装这个包用python -m pip install yagmail安装安装后仍报相同错误运行脚本的 Python 和安装包的 Python 不是同一个环境检查python -c import sys; print(sys.executable)externally-managed-environment系统 Python 受 PEP 668 保护创建并激活虚拟环境后再安装Defaulting to user installation because normal site-packages is not writeable当前用户对 site-packages 无写权限优先使用虚拟环境或使用--user装用户目录WARNING: You are using pip version 21.1.1pip 版本太旧python -m pip install --upgrade pipReadTimeoutError或连接被重置网络到默认源不稳定使用国内镜像源或增加--timeout和--retries某个import报错但包明明存在同名下其他包干扰或者工作目录错位在正确环境里重装并用python -c import xxx验证这张表看起来简单但覆盖了我这些年处理 Python 导入类报错时遇到的大多数情况。可以说光是把“python -m pip”和“确认当前解释器路径”这两个习惯养成市面上 70% 的ModuleNotFoundError都影响不到你。6.2 我处理这类问题时的几条个人习惯最后把我自己的一套操作流程分享出来。新建一个 Python 项目时我永远先执行python -m venv venv然后激活虚拟环境。激活完先看一眼提示符前有没有环境名再顺手把 pip 升到最新版。接下来才是安装项目需要的依赖并第一时间把依赖列表固化到requirements.txt里。等到项目收敛需要部署到新机器时一条pip install -r requirements.txt就能复现完整环境而不是靠记忆“当时好像装过那几个包”。遇到报错时我从来不追着错误信息死磕而是先把当前的sys.path和sys.executable打印出来。确认环境再看报错往往问题已经解决一半。如果我想在群里或者社区问别人我会一次性把python --version、python -m pip --version、完整的报错日志这三样信息贴出来。很多人只甩一句“我装不上”没有版本信息、没有日志神仙也难一眼定因。说实话像ModuleNotFoundError: No module named yagmail这种报错几乎每个用过 Python 的人都会遇到。它看着简单把你卡住的时间可能比任何高级特性都长。学会把自己从“只会写代码的人”变成“会管理环境的人”你往后的 Python 路上会顺很多。
返回列表