outlookEmail 支持 Outlook/Hotmail、Gmail、QQ、163、126、Yahoo、阿里邮箱以及自定义 IMAP 邮箱,同时集成 GPTMail、DuckMail、Cloudflare Temp Email 多提供商临时邮箱能力
Python
1,742
174 commits
updated Oct 15, 2026
一个面向多邮箱账号场景的邮件管理工具,支持通过 Outlook/Hotmail OAuth、Microsoft Graph API 和标准 IMAP 统一读取、管理和转发邮件,并提供 Web 界面、Chrome/Edge 浏览器扩展,用于分组管理、账号管理、邮件查看和对外 API 调用。当前支持 Outlook/Hotmail、Gmail、QQ、163、126、Yahoo、阿里邮箱以及自定义 IMAP 邮箱,同时集成 GPTMail、DuckMail、Cloudflare Temp Email 多提供商临时邮箱能力。
注意:改密码会导致auth失效,需要重新授权
https://aso.de5.net admin123 注意:体验站点请勿修改密码或存放实际数据,部署在无持久化的服务上,数据随时可能丢失恢复初始状态;并且由于大家都能登录看到,并且好像有进程在扫描,所以非常可能存在账号被盗的风险
本项目采用轻量化双分支版本管理:main 为稳定发布分支,dev 为日常开发分支。
完整的发版步骤、工作流行为和核对清单见 发版说明。
exe(win可用)从 GitHub Releases 下载对应版本的 OutlookEmail-windows-x64-*.zip,解压后直接运行 OutlookEmail.exe 即可。
Windows 桌面版发现新版本后,可在页面顶部的版本入口点击「立即升级」。确认后应用会把现有 Release ZIP 下载到当前 EXE 所在目录,显示下载百分比和速度,完成后自动替换并重启;下载阶段可以取消。
桌面版首次启动会自动:
SECRET_KEYhttp://127.0.0.1:5000说明:
%APPDATA%\OutlookEmail*.old.exe 手动改回原文件名恢复admin123,首次登录后建议立即修改从 GitHub Releases 下载对应架构的 OutlookEmail-macos-*-*.dmg,打开后把 OutlookEmail.app 拖到 Applications 即可。
桌面版首次启动会自动:
SECRET_KEYhttp://127.0.0.1:5000说明:
~/Library/Application Support/OutlookEmailsudo xattr -rd com.apple.quarantine /Applications/OutlookEmail.appadmin123,首次登录后建议立即修改# 拉取最新镜像
docker pull ghcr.io/assast/outlookemail:latest
# 运行容器
docker run -d \
--name outlook-mail-reader \
-p 5000:5000 \
-v $(pwd)/data:/app/data \
-e LOGIN_PASSWORD=admin123 \
-e SECRET_KEY=your-secret-key-here \
ghcr.io/assast/outlookemail:latest
git clone https://github.com/assast/outlookEmail.git
cd outlookEmail
pip install -r requirements.txt
export SECRET_KEY=your-secret-key-here
python web_outlook_app.py
python -m pip install -r requirements.txt; $env:SECRET_KEY = (& python -c "import secrets; print(secrets.token_hex(32))")[0]; $env:HOST="127.0.0.1"; python web_outlook_app.py
访问 http://localhost:5000 即可使用。
如果是服务器部署,仍然建议显式设置固定 SECRET_KEY。
服务需要保持单 worker 运行。官方 Docker 镜像已固定为 Gunicorn 单 worker + 多线程;如果自定义部署,请不要增加 worker 数,需要并发时优先调整线程数。Token 刷新管理的流式任务会使用进程内短期状态,多个 worker 会导致任务初始化和 SSE 订阅落到不同进程。
version: '3.8'
services:
outlook-mail-reader:
image: ghcr.io/assast/outlookemail:latest
container_name: outlook-mail-reader
ports:
- "5000:5000"
volumes:
- ./data:/app/data
environment:
- LOGIN_PASSWORD=admin123
- SECRET_KEY=your-secret-key-here
- FLASK_ENV=production
restart: unless-stopped
docker-compose up -d
界面里的 Docker 在线更新需要访问宿主机 Docker socket。/var/run/docker.sock 具有宿主机 Docker 管理权限,只建议在可信环境开启。
该功能只适用于使用可变镜像标签的容器,例如 latest、main、dev。如果当前容器固定使用 v2.0.39 这类版本标签,界面会拒绝在线更新,因为 Watchtower 不会自动把固定标签切换到新版本标签。
应用默认会在 daemon 明确返回“最低支持 API 版本”时自动按该版本重试;如果你的 Docker 环境或 socket 代理有特殊兼容要求,也可以显式设置 DOCKER_UPDATE_API_VERSION,其值可参考 docker version --format '{{.Server.APIVersion}}' 的输出。
可选环境变量 DOCKER_UPDATE_STATUS_TIMEOUT 用于单独控制状态查询和容器 inspect 的超时时间(秒),不影响实际更新任务的 DOCKER_UPDATE_TIMEOUT。
如果当前 latest / main / dev 标签没有新的镜像可拉取,界面会显示本次没有应用更新,而不是误报为更新失败。
如果想让界面里的「获取 Token」使用自己的 Azure 应用,请同时设置 OAUTH_CLIENT_ID 和 OAUTH_REDIRECT_URI。这两个值会用于生成 Microsoft 授权链接和换取 Refresh Token;换取成功后界面返回的 Client ID 需要和 Refresh Token 一起导入账号。未设置时会使用项目内置的默认 Client ID 和默认回调地址 http://localhost:8080。
version: '3.8'
services:
outlook-mail-reader:
image: ghcr.io/assast/outlookemail:latest
container_name: outlook-mail-reader
ports:
- "5000:5000"
volumes:
- ./data:/app/data
- /var/run/docker.sock:/var/run/docker.sock
environment:
- LOGIN_PASSWORD=admin123
- SECRET_KEY=your-secret-key-here
- FLASK_ENV=production
- DOCKER_UPDATE_ENABLED=true
- DOCKER_UPDATE_CONTAINER=outlook-mail-reader
# 可选:在较新的 Docker daemon / socket 代理环境中显式指定 API 版本
# - DOCKER_UPDATE_API_VERSION=1.52
# 可选:让界面 OAuth 助手使用你自己的 Azure 应用
# - OAUTH_CLIENT_ID=your-azure-application-client-id
# - OAUTH_REDIRECT_URI=http://localhost:8080
restart: unless-stopped
适合在本机基于源码自行构建镜像(而非拉取 ghcr.io 上的预构建镜像)后运行,便于本地改动后立即验证。
仓库根目录已提供 docker-compose.build.yml,它会用根目录的 Dockerfile 从源码构建镜像并启动容器。
.env.localdocker-compose.build.yml 通过 env_file: .env.local 注入环境变量,该文件不存在时 Compose 会直接报错拒绝启动,需先从模板复制并修改:
cp .env.example .env.local
至少修改以下两项:
# 生成随机串后填入 .env.local 的 SECRET_KEY
python -c 'import secrets; print(secrets.token_hex(32))'
SECRET_KEY:填入上面生成的随机串(务必修改,勿用占位值;首尾空白会被忽略)LOGIN_PASSWORD:首次初始化时的登录密码,默认 admin123,建议改为强密码;已写入数据库后再改此变量不会覆盖当前密码。忘记密码请用 scripts/reset_login_password.py(见 故障排除 / 安全配置)可选:如需调整 Gunicorn 线程数 / 超时,在 .env.local 中追加 GUNICORN_THREADS、GUNICORN_TIMEOUT(不填则使用默认值 4 / 300)。
可选:普通 Outlook/IMAP 邮箱读取邮件列表的整体超时默认为 120 秒,可在「系统设置 -> 常规设置 -> 邮件获取超时」中调整(30-300 秒);也可在首次启动前通过 .env.local 的 MAIL_FETCH_OVERALL_TIMEOUT 设置初始值。该值应小于 GUNICORN_TIMEOUT(默认 300 秒)。
docker compose -f docker-compose.build.yml up -d --build
--build 强制从源码重新构建镜像(镜像标签为 outlookemail:local)outlook-mail,映射端口 5000:5000./data;./static、./templates 以只读方式挂载,便于本地编辑模板/静态资源实时生效启动后访问 http://localhost:5000,使用 .env.local 中的 LOGIN_PASSWORD 登录。
# 查看日志
docker compose -f docker-compose.build.yml logs -f
# 查看健康检查与状态
docker compose -f docker-compose.build.yml ps
# 改动源码后重新构建并重启
docker compose -f docker-compose.build.yml up -d --build
# 停止并移除容器(数据仍保留在 ./data)
docker compose -f docker-compose.build.yml down
提示:
docker-compose.build.yml默认未挂载宿主机 Docker socket,因此界面里的「Docker 在线更新」不可用——本地构建场景请直接用上面的up -d --build重新构建来更新。
本工具当前包含三类读取链路:
outlook.live.com / outlook.office365.com普通邮箱本地保留开关 normal_mail_local_retention_enabled 默认关闭。用户需要在系统设置中明确开启后,普通 Outlook/Hotmail 与标准 IMAP 邮箱才会把列表元数据和已查看、补齐过的部分正文保存到本机 SQLite。
开启后,普通邮箱列表会优先从本地保留数据加载,命中时可立即显示最近一次保留的邮件列表;在本地优先模式下继续向下滚动加载更多,也会沿用本地保留分页,因此远程不可用时仍可查看超过首屏的已保留邮件。页面同时会在后台继续向 Graph API 或 IMAP 发起远程同步。远程同步成功后会把新列表元数据写回本地保留库;同步失败时,当前页面会保留本地列表并显示后台同步失败提示,而不会把列表清空。
后台同步发现本地尚未显示的新邮件时,页面会显示“有 N 封新邮件已同步”的非打断式提示。同步成功不会立即把新邮件并入当前列表;用户点击提示后,新邮件才会合并到当前列表,并执行高亮、列表缓存更新和新邮件正文保留的后台补齐,避免正在阅读或已选择的邮件被突然替换。
邮件详情会优先使用已保留的正文内容;如果本地行还没有正文,远程详情读取成功后会回填正文保留数据,供后续刷新页面、重启应用或临时网络失败时继续查看。若远程详情失败但本地已有正文,详情页会展示本地保留正文作为回退。关键词过滤也会先检查已缓存正文,只有缓存缺失时才补走远程详情读取。
Outlook/Hotmail OAuth 的 IMAP 回退链路默认按 UID 读取详情和附件;列表项、详情请求和附件下载可携带 id_mode=uid|sequence,避免 UID 与序列号混用导致取错邮件。标准 IMAP 账号继续使用其既有消息 ID 读取逻辑。
当前阶段只保留普通邮箱列表元数据和已读取过的详情正文,不包含附件二进制、原始 MIME 内容的下载或保留;附件下载仍依赖当前远程提供商链路。设置页会显示已保存邮件数、已缓存正文数、估算保留大小和当前 SQLite 数据库大小,并提供独立“清理缓存”操作。关闭本地保留开关时,界面会先要求确认;确认后会通过后台清理任务删除普通邮箱本地保留数据,并显示清理状态。清理任务会拒绝重复启动、对 SQLite 短暂锁进行有限重试,前端状态轮询使用退避间隔减少长任务压力。更完整的范围说明见 docs/local-mail-retention.md。
scripts/reset_login_password.py 重置(见 故障排除){mail} 占位符(对接 Resin 等粘性代理池)inbox、junkemail、deleteditems、all1–50 封邮件Web 应用采用四栏式布局设计:





要使用本工具,您需要获取以下 OAuth2 凭证:
界面中的 OAuth2 助手会读取服务启动时的 OAUTH_CLIENT_ID 和 OAUTH_REDIRECT_URI。如果你在 Docker / Docker Compose 里配置了自己的值,授权链接和换取 Token 都会使用这些值;如果没有配置,则使用项目内置默认值。账号导入时,Client ID 要和同一次授权换出的 Refresh Token 配套使用。
访问 Azure Portal,进入「应用注册」:

点击「新注册」,填写应用信息:

http://localhost:8080创建完成后,复制「应用程序(客户端) ID」:

手动 OAuth 助手默认走 GraphAPI 单资源权限,避免 Microsoft OAuth v2 在同一次授权中混用 Graph 和 Outlook 资源时报 AADSTS70011:
offline_access - 获取刷新令牌Mail.Read / Mail.ReadWrite / Mail.Send / User.Read - Graph 读信、邮件管理、以当前账号自身身份发信与基本用户信息Mail.Send 是 Web 端基础写邮件所需的委托权限。历史 Refresh Token 无法静默增加该权限;如果写邮件时提示权限不足,请对该账号重新完成一次 GraphAPI 授权。重新授权不会影响已有的读信配置。
如需 IMAP 访问,请在「Outlook邮箱授权」面板选择 IMAP授权(自动授权默认是 GraphAPI),不要和 Graph 权限放在同一次手动授权链接里。IMAP 授权不包含 Mail.Send,也不支持 Web 端基础写邮件。
使用本工具内置的 OAuth2 助手获取 Refresh Token:

在 Web 界面中点击「导入邮箱」后,可根据邮箱类型选择对应导入格式。
支持两种格式:
邮箱----密码----client_id----refresh_token
邮箱----密码----refresh_token----client_id
示例:
user@outlook.com----password123----24d9a0ed-8787-4584-883c-2fd79308940a----0.AXEA...
适用于 Gmail、QQ、163、126、Yahoo、阿里邮箱等:
邮箱----IMAP授权码/应用密码
示例:
user@gmail.com----app-password
user@qq.com----imap-auth-code
支持两种格式:
邮箱----IMAP密码
邮箱----IMAP密码----imap_host----imap_port
示例:
user@example.com----app-password
user@example.com----app-password----imap.example.com----993
支持批量导入,每行一个账号。导入文件格式保持不变;导入弹窗可为本次新增账号统一设置备注、标签、状态,并可选择是否立即开启邮件转发。普通邮箱导入时不能选择临时邮箱分组。
分组支持最多三级层级。选中父分组时,邮箱账号列表会同时展示该分组和所有子分组下的账号;子分组未配置代理时会向上继承父级分组代理。删除含子分组的分组会级联删除子分组,并把相关账号移回默认分组。
{mail} 模板分组或账号代理 URL 可包含字面量 {mail}。出站请求(拉信、Token 刷新、Outlook 自动授权等)会在运行时替换为邮箱 @ 前 local-part:去掉非字母数字字符并转小写。配置原样存库,编辑回显不展开。
推荐示例(Resin 默认端口 2260,V1 粘性身份 Platform.Account:TOKEN):
socks5h://outlook.{mail}:你的Token@127.0.0.1:2260
Token 为空时以下两种均可:
socks5h://outlook.{mail}:@127.0.0.1:2260
socks5h://outlook.{mail}@127.0.0.1:2260
说明:
socks5h:// / socks5://;普通 HTTP 代理对 IMAP 令牌请求可能不可用a.b 与 ab),本项目接受该行为proxy_url,否则继承分组代理模板LOG_LEVEL=INFO 会在拉信 / Token 刷新 / 自动授权时打印 [代理] 详情(密码打码)。批量场景日志较多时,设 LOG_LEVEL=WARNING 即可降噪关闭这类 INFOdeleteditems 或 all 聚合结果时,建议使用对外 API 或内部 API选择一个已启用、通过 GraphAPI 授权的 Outlook/Hotmail 主账号后,邮件列表顶部会显示「写邮件」。该功能仅支持以当前账号自身身份向一个或多个收件人发送纯文本邮件:
GraphAPI 授权以获取 Mail.Send。202 Accepted 时,界面会显示“邮件已提交发送”;这表示服务已接受请求,不等同于收件人已送达。在邮箱账号的分享操作中可创建可撤销的只读链接。创建时可选择「不限量」或「仅最新 N 封」;后者可设置 1–50,并将收件箱和垃圾邮件合并后只展示当前最新的 N 封邮件。
邮箱账号列表左侧有选择框,适合对多个账号同时刷新 Token、复制邮箱、修改转发状态、打标签、移动分组或删除。
常用选择方式:
Shift 点击另一个账号或选择框,会选中两者之间的连续范围。选中至少一个账号后,会出现批量菜单:
普通邮箱账号支持的批量操作:
临时邮箱分组也使用同一套选择方式,但批量菜单只显示适用于临时邮箱的操作,例如复制邮箱、标签添加/移除和删除;刷新 Token、转发开关、移动分组等普通账号专属操作会隐藏。
按分组导出时会包含所选分组及其所有子分组账号;如果同时选中了父分组和子分组,导出内容会自动去重。
「Token刷新管理」里的邮箱列表也支持同一套批量选择方式:
Shift 连续范围选择或拖拽选择账号。选中账号后可直接执行这些批量动作:
普通邮箱的邮件列表左侧也有选择框,适合批量处理当前邮箱的邮件:
邮件批量选择只作用于当前邮箱当前文件夹/聚合视图里已经加载的邮件;切换邮箱、刷新邮件列表或列表为空时,已选邮件会被清空。
适合这些场景:
user+tag@example.com邮件转发分成两层控制:
补充说明:
在「设置 -> WebDAV 备份」中配置:
https://dav.example.com/backups0 3 * * *补充说明:
all_groups_backup_YYYYMMDD_HHMMSS.txthttps://dav.jianguoyun.com/dav/mailBackup;不要只填写 https://dav.jianguoyun.com/dav仓库内置 Chrome / Edge Manifest V3 扩展,目录为 browser-extension/。扩展使用 Web 端登录密码,不需要对外 API Key。
安装方式:
chrome://extensions/ 或 edge://extensions/browser-extension 目录使用方式:
扩展会在浏览器侧边栏内提供原生操作面板,当前网页标签不会被切走。现在可直接使用邮箱、导入、刷新、Token、导出、标签和设置等功能。完整安装、配置、功能和故障排查说明见 浏览器扩展使用说明。
通过 API Key 直接获取邮件,无需登录 Web 界面。
当前额外支持:
folder=all 一次聚合收件箱和垃圾邮件并按标准化后的邮件时间倒序排序,top 按每个文件夹分别计算user+alias@example.com@gmail.com / @googlemail.com 地址时,原后缀未命中会自动回退到另一个后缀top=1skip / top 会做安全解析:非数字使用默认值,负数按 0 处理;top 最大 50配置步骤:
调用示例:
curl -H "X-API-Key: your-api-key" \
"http://localhost:5000/api/external/emails?email=user@outlook.com&folder=inbox"
curl -H "X-API-Key: your-api-key" \
"http://localhost:5000/api/external/emails?email=alias@example.com&folder=all&top=10"
curl -H "X-API-Key: your-api-key" \
"http://localhost:5000/api/external/emails?email=alias@example.com&folder=all&top=10&subject_contains=verify&from_contains=github&keyword=reset"
curl -H "X-API-Key: your-api-key" \
"http://localhost:5000/api/external/emails?email=user%2Balias%40example.com"
如果邮箱或别名里带特殊字符:
@ 可以直接传+ 建议编码成 %2B& 必须编码成 %26如果你把外部邮箱 B 自动转发到本项目管理的邮箱 A,再把 B 配成 A 的别名,那么后续可以直接用 B 作为 email 参数调用对外 API。
详细文档见 API 文档。
| 文档 | 说明 |
|---|---|
| 🚀 部署指南 | Docker、Docker Compose、Nginx/Caddy 部署、环境变量配置 |
| ⬆️ 升级指南 | Windows、Docker、Python 直跑升级与回滚建议 |
| 🔐 安全配置 | XSS/CSRF 防护、数据加密、速率限制、审计日志 |
| 🎭 外观皮肤 | 系统级皮肤、zip 上传、Git 仓库来源、皮肤包格式与持久化说明 |
| 📡 API 文档 | 对外简易API、完整API、代理配置 |
| 🛠️ 故障排查 | 常见问题、故障排查步骤 |
| 📋 更新日志 | 版本更新历史 |
| 🚢 发版说明 | 标准发版步骤、版本号规则、GitHub Release 说明 |
| 🛡️ 分支保护建议 | main/dev 使用边界、保护规则与构建触发建议 |
flask>=3.0.0
flask-wtf>=1.2.0 # CSRF 防护(推荐安装)
werkzeug>=3.0.0
requests[socks]>=2.25.0 # HTTP 请求与代理支持
APScheduler>=3.10.0 # 定时任务
croniter>=1.3.0 # Cron 表达式解析
bcrypt>=4.0.0 # 密码哈希
cryptography>=41.0.0 # 数据加密
开启2fa,然后在这里创建应用密码
https://support.google.com/mail/answer/185833?hl=zh-Hans
在 Telegram 搜索框搜索 @userinfobot 或 @getmyid_bot。
点击 Start。
机器人会立即回复你的 User ID(一串数字)。
如果你想知道别人的 ID:只需将对方发给你的消息转发给这个机器人,它就会显示该用户的 ID。
将上述机器人(如 @getmyid_bot)拉进你的群组。
在群组里输入 /myid(或者机器人指定的指令)。
机器人会返回该群组的 ID。
注意: 普通群组 ID 通常以数字开头,而**超级群组(Supergroup)或频道(Channel)**的 ID 通常以 -100 开头。
欢迎提交 Issue 和 Pull Request!
git clone https://github.com/assast/outlookEmail.git
cd outlookEmail
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python web_outlook_app.py
MIT License - 详见 LICENSE
本项目已在 LINUX DO 社区 发布,感谢社区的支持与反馈。
⭐ 如果这个项目对你有帮助,请给个 Star 支持一下!你的 Star 是我持续更新的动力! ⭐
初次维护一个项目,2026年04月11日15:45:33才发现有几个pull没合并,非常抱歉,这是我的联系方式如果我没看到的话,可以提醒我一下,有好的建议也可以提,感谢~ 邮箱:u3794336@outlook.com
本项目仅供学习、研究和技术交流使用,请遵守相关平台和服务条款,不要用于违规、滥用或非法用途。 因使用本项目产生的任何风险和后果,由使用者自行承担。
outlookEmail 支持 Outlook/Hotmail、Gmail、QQ、163、126、Yahoo、阿里邮箱以及自定义 IMAP 邮箱,同时集成 GPTMail、DuckMail、Cloudflare Temp Email 多提供商临时邮箱能力
Python
1,742
174 commits
updated Oct 15, 2026
一个面向多邮箱账号场景的邮件管理工具,支持通过 Outlook/Hotmail OAuth、Microsoft Graph API 和标准 IMAP 统一读取、管理和转发邮件,并提供 Web 界面、Chrome/Edge 浏览器扩展,用于分组管理、账号管理、邮件查看和对外 API 调用。当前支持 Outlook/Hotmail、Gmail、QQ、163、126、Yahoo、阿里邮箱以及自定义 IMAP 邮箱,同时集成 GPTMail、DuckMail、Cloudflare Temp Email 多提供商临时邮箱能力。
注意:改密码会导致auth失效,需要重新授权
https://aso.de5.net admin123 注意:体验站点请勿修改密码或存放实际数据,部署在无持久化的服务上,数据随时可能丢失恢复初始状态;并且由于大家都能登录看到,并且好像有进程在扫描,所以非常可能存在账号被盗的风险
本项目采用轻量化双分支版本管理:main 为稳定发布分支,dev 为日常开发分支。
完整的发版步骤、工作流行为和核对清单见 发版说明。
exe(win可用)从 GitHub Releases 下载对应版本的 OutlookEmail-windows-x64-*.zip,解压后直接运行 OutlookEmail.exe 即可。
Windows 桌面版发现新版本后,可在页面顶部的版本入口点击「立即升级」。确认后应用会把现有 Release ZIP 下载到当前 EXE 所在目录,显示下载百分比和速度,完成后自动替换并重启;下载阶段可以取消。
桌面版首次启动会自动:
SECRET_KEYhttp://127.0.0.1:5000说明:
%APPDATA%\OutlookEmail*.old.exe 手动改回原文件名恢复admin123,首次登录后建议立即修改从 GitHub Releases 下载对应架构的 OutlookEmail-macos-*-*.dmg,打开后把 OutlookEmail.app 拖到 Applications 即可。
桌面版首次启动会自动:
SECRET_KEYhttp://127.0.0.1:5000说明:
~/Library/Application Support/OutlookEmailsudo xattr -rd com.apple.quarantine /Applications/OutlookEmail.appadmin123,首次登录后建议立即修改# 拉取最新镜像
docker pull ghcr.io/assast/outlookemail:latest
# 运行容器
docker run -d \
--name outlook-mail-reader \
-p 5000:5000 \
-v $(pwd)/data:/app/data \
-e LOGIN_PASSWORD=admin123 \
-e SECRET_KEY=your-secret-key-here \
ghcr.io/assast/outlookemail:latest
git clone https://github.com/assast/outlookEmail.git
cd outlookEmail
pip install -r requirements.txt
export SECRET_KEY=your-secret-key-here
python web_outlook_app.py
python -m pip install -r requirements.txt; $env:SECRET_KEY = (& python -c "import secrets; print(secrets.token_hex(32))")[0]; $env:HOST="127.0.0.1"; python web_outlook_app.py
访问 http://localhost:5000 即可使用。
如果是服务器部署,仍然建议显式设置固定 SECRET_KEY。
服务需要保持单 worker 运行。官方 Docker 镜像已固定为 Gunicorn 单 worker + 多线程;如果自定义部署,请不要增加 worker 数,需要并发时优先调整线程数。Token 刷新管理的流式任务会使用进程内短期状态,多个 worker 会导致任务初始化和 SSE 订阅落到不同进程。
version: '3.8'
services:
outlook-mail-reader:
image: ghcr.io/assast/outlookemail:latest
container_name: outlook-mail-reader
ports:
- "5000:5000"
volumes:
- ./data:/app/data
environment:
- LOGIN_PASSWORD=admin123
- SECRET_KEY=your-secret-key-here
- FLASK_ENV=production
restart: unless-stopped
docker-compose up -d
界面里的 Docker 在线更新需要访问宿主机 Docker socket。/var/run/docker.sock 具有宿主机 Docker 管理权限,只建议在可信环境开启。
该功能只适用于使用可变镜像标签的容器,例如 latest、main、dev。如果当前容器固定使用 v2.0.39 这类版本标签,界面会拒绝在线更新,因为 Watchtower 不会自动把固定标签切换到新版本标签。
应用默认会在 daemon 明确返回“最低支持 API 版本”时自动按该版本重试;如果你的 Docker 环境或 socket 代理有特殊兼容要求,也可以显式设置 DOCKER_UPDATE_API_VERSION,其值可参考 docker version --format '{{.Server.APIVersion}}' 的输出。
可选环境变量 DOCKER_UPDATE_STATUS_TIMEOUT 用于单独控制状态查询和容器 inspect 的超时时间(秒),不影响实际更新任务的 DOCKER_UPDATE_TIMEOUT。
如果当前 latest / main / dev 标签没有新的镜像可拉取,界面会显示本次没有应用更新,而不是误报为更新失败。
如果想让界面里的「获取 Token」使用自己的 Azure 应用,请同时设置 OAUTH_CLIENT_ID 和 OAUTH_REDIRECT_URI。这两个值会用于生成 Microsoft 授权链接和换取 Refresh Token;换取成功后界面返回的 Client ID 需要和 Refresh Token 一起导入账号。未设置时会使用项目内置的默认 Client ID 和默认回调地址 http://localhost:8080。
version: '3.8'
services:
outlook-mail-reader:
image: ghcr.io/assast/outlookemail:latest
container_name: outlook-mail-reader
ports:
- "5000:5000"
volumes:
- ./data:/app/data
- /var/run/docker.sock:/var/run/docker.sock
environment:
- LOGIN_PASSWORD=admin123
- SECRET_KEY=your-secret-key-here
- FLASK_ENV=production
- DOCKER_UPDATE_ENABLED=true
- DOCKER_UPDATE_CONTAINER=outlook-mail-reader
# 可选:在较新的 Docker daemon / socket 代理环境中显式指定 API 版本
# - DOCKER_UPDATE_API_VERSION=1.52
# 可选:让界面 OAuth 助手使用你自己的 Azure 应用
# - OAUTH_CLIENT_ID=your-azure-application-client-id
# - OAUTH_REDIRECT_URI=http://localhost:8080
restart: unless-stopped
适合在本机基于源码自行构建镜像(而非拉取 ghcr.io 上的预构建镜像)后运行,便于本地改动后立即验证。
仓库根目录已提供 docker-compose.build.yml,它会用根目录的 Dockerfile 从源码构建镜像并启动容器。
.env.localdocker-compose.build.yml 通过 env_file: .env.local 注入环境变量,该文件不存在时 Compose 会直接报错拒绝启动,需先从模板复制并修改:
cp .env.example .env.local
至少修改以下两项:
# 生成随机串后填入 .env.local 的 SECRET_KEY
python -c 'import secrets; print(secrets.token_hex(32))'
SECRET_KEY:填入上面生成的随机串(务必修改,勿用占位值;首尾空白会被忽略)LOGIN_PASSWORD:首次初始化时的登录密码,默认 admin123,建议改为强密码;已写入数据库后再改此变量不会覆盖当前密码。忘记密码请用 scripts/reset_login_password.py(见 故障排除 / 安全配置)可选:如需调整 Gunicorn 线程数 / 超时,在 .env.local 中追加 GUNICORN_THREADS、GUNICORN_TIMEOUT(不填则使用默认值 4 / 300)。
可选:普通 Outlook/IMAP 邮箱读取邮件列表的整体超时默认为 120 秒,可在「系统设置 -> 常规设置 -> 邮件获取超时」中调整(30-300 秒);也可在首次启动前通过 .env.local 的 MAIL_FETCH_OVERALL_TIMEOUT 设置初始值。该值应小于 GUNICORN_TIMEOUT(默认 300 秒)。
docker compose -f docker-compose.build.yml up -d --build
--build 强制从源码重新构建镜像(镜像标签为 outlookemail:local)outlook-mail,映射端口 5000:5000./data;./static、./templates 以只读方式挂载,便于本地编辑模板/静态资源实时生效启动后访问 http://localhost:5000,使用 .env.local 中的 LOGIN_PASSWORD 登录。
# 查看日志
docker compose -f docker-compose.build.yml logs -f
# 查看健康检查与状态
docker compose -f docker-compose.build.yml ps
# 改动源码后重新构建并重启
docker compose -f docker-compose.build.yml up -d --build
# 停止并移除容器(数据仍保留在 ./data)
docker compose -f docker-compose.build.yml down
提示:
docker-compose.build.yml默认未挂载宿主机 Docker socket,因此界面里的「Docker 在线更新」不可用——本地构建场景请直接用上面的up -d --build重新构建来更新。
本工具当前包含三类读取链路:
outlook.live.com / outlook.office365.com普通邮箱本地保留开关 normal_mail_local_retention_enabled 默认关闭。用户需要在系统设置中明确开启后,普通 Outlook/Hotmail 与标准 IMAP 邮箱才会把列表元数据和已查看、补齐过的部分正文保存到本机 SQLite。
开启后,普通邮箱列表会优先从本地保留数据加载,命中时可立即显示最近一次保留的邮件列表;在本地优先模式下继续向下滚动加载更多,也会沿用本地保留分页,因此远程不可用时仍可查看超过首屏的已保留邮件。页面同时会在后台继续向 Graph API 或 IMAP 发起远程同步。远程同步成功后会把新列表元数据写回本地保留库;同步失败时,当前页面会保留本地列表并显示后台同步失败提示,而不会把列表清空。
后台同步发现本地尚未显示的新邮件时,页面会显示“有 N 封新邮件已同步”的非打断式提示。同步成功不会立即把新邮件并入当前列表;用户点击提示后,新邮件才会合并到当前列表,并执行高亮、列表缓存更新和新邮件正文保留的后台补齐,避免正在阅读或已选择的邮件被突然替换。
邮件详情会优先使用已保留的正文内容;如果本地行还没有正文,远程详情读取成功后会回填正文保留数据,供后续刷新页面、重启应用或临时网络失败时继续查看。若远程详情失败但本地已有正文,详情页会展示本地保留正文作为回退。关键词过滤也会先检查已缓存正文,只有缓存缺失时才补走远程详情读取。
Outlook/Hotmail OAuth 的 IMAP 回退链路默认按 UID 读取详情和附件;列表项、详情请求和附件下载可携带 id_mode=uid|sequence,避免 UID 与序列号混用导致取错邮件。标准 IMAP 账号继续使用其既有消息 ID 读取逻辑。
当前阶段只保留普通邮箱列表元数据和已读取过的详情正文,不包含附件二进制、原始 MIME 内容的下载或保留;附件下载仍依赖当前远程提供商链路。设置页会显示已保存邮件数、已缓存正文数、估算保留大小和当前 SQLite 数据库大小,并提供独立“清理缓存”操作。关闭本地保留开关时,界面会先要求确认;确认后会通过后台清理任务删除普通邮箱本地保留数据,并显示清理状态。清理任务会拒绝重复启动、对 SQLite 短暂锁进行有限重试,前端状态轮询使用退避间隔减少长任务压力。更完整的范围说明见 docs/local-mail-retention.md。
scripts/reset_login_password.py 重置(见 故障排除){mail} 占位符(对接 Resin 等粘性代理池)inbox、junkemail、deleteditems、all1–50 封邮件Web 应用采用四栏式布局设计:





要使用本工具,您需要获取以下 OAuth2 凭证:
界面中的 OAuth2 助手会读取服务启动时的 OAUTH_CLIENT_ID 和 OAUTH_REDIRECT_URI。如果你在 Docker / Docker Compose 里配置了自己的值,授权链接和换取 Token 都会使用这些值;如果没有配置,则使用项目内置默认值。账号导入时,Client ID 要和同一次授权换出的 Refresh Token 配套使用。
访问 Azure Portal,进入「应用注册」:

点击「新注册」,填写应用信息:

http://localhost:8080创建完成后,复制「应用程序(客户端) ID」:

手动 OAuth 助手默认走 GraphAPI 单资源权限,避免 Microsoft OAuth v2 在同一次授权中混用 Graph 和 Outlook 资源时报 AADSTS70011:
offline_access - 获取刷新令牌Mail.Read / Mail.ReadWrite / Mail.Send / User.Read - Graph 读信、邮件管理、以当前账号自身身份发信与基本用户信息Mail.Send 是 Web 端基础写邮件所需的委托权限。历史 Refresh Token 无法静默增加该权限;如果写邮件时提示权限不足,请对该账号重新完成一次 GraphAPI 授权。重新授权不会影响已有的读信配置。
如需 IMAP 访问,请在「Outlook邮箱授权」面板选择 IMAP授权(自动授权默认是 GraphAPI),不要和 Graph 权限放在同一次手动授权链接里。IMAP 授权不包含 Mail.Send,也不支持 Web 端基础写邮件。
使用本工具内置的 OAuth2 助手获取 Refresh Token:

在 Web 界面中点击「导入邮箱」后,可根据邮箱类型选择对应导入格式。
支持两种格式:
邮箱----密码----client_id----refresh_token
邮箱----密码----refresh_token----client_id
示例:
user@outlook.com----password123----24d9a0ed-8787-4584-883c-2fd79308940a----0.AXEA...
适用于 Gmail、QQ、163、126、Yahoo、阿里邮箱等:
邮箱----IMAP授权码/应用密码
示例:
user@gmail.com----app-password
user@qq.com----imap-auth-code
支持两种格式:
邮箱----IMAP密码
邮箱----IMAP密码----imap_host----imap_port
示例:
user@example.com----app-password
user@example.com----app-password----imap.example.com----993
支持批量导入,每行一个账号。导入文件格式保持不变;导入弹窗可为本次新增账号统一设置备注、标签、状态,并可选择是否立即开启邮件转发。普通邮箱导入时不能选择临时邮箱分组。
分组支持最多三级层级。选中父分组时,邮箱账号列表会同时展示该分组和所有子分组下的账号;子分组未配置代理时会向上继承父级分组代理。删除含子分组的分组会级联删除子分组,并把相关账号移回默认分组。
{mail} 模板分组或账号代理 URL 可包含字面量 {mail}。出站请求(拉信、Token 刷新、Outlook 自动授权等)会在运行时替换为邮箱 @ 前 local-part:去掉非字母数字字符并转小写。配置原样存库,编辑回显不展开。
推荐示例(Resin 默认端口 2260,V1 粘性身份 Platform.Account:TOKEN):
socks5h://outlook.{mail}:你的Token@127.0.0.1:2260
Token 为空时以下两种均可:
socks5h://outlook.{mail}:@127.0.0.1:2260
socks5h://outlook.{mail}@127.0.0.1:2260
说明:
socks5h:// / socks5://;普通 HTTP 代理对 IMAP 令牌请求可能不可用a.b 与 ab),本项目接受该行为proxy_url,否则继承分组代理模板LOG_LEVEL=INFO 会在拉信 / Token 刷新 / 自动授权时打印 [代理] 详情(密码打码)。批量场景日志较多时,设 LOG_LEVEL=WARNING 即可降噪关闭这类 INFOdeleteditems 或 all 聚合结果时,建议使用对外 API 或内部 API选择一个已启用、通过 GraphAPI 授权的 Outlook/Hotmail 主账号后,邮件列表顶部会显示「写邮件」。该功能仅支持以当前账号自身身份向一个或多个收件人发送纯文本邮件:
GraphAPI 授权以获取 Mail.Send。202 Accepted 时,界面会显示“邮件已提交发送”;这表示服务已接受请求,不等同于收件人已送达。在邮箱账号的分享操作中可创建可撤销的只读链接。创建时可选择「不限量」或「仅最新 N 封」;后者可设置 1–50,并将收件箱和垃圾邮件合并后只展示当前最新的 N 封邮件。
邮箱账号列表左侧有选择框,适合对多个账号同时刷新 Token、复制邮箱、修改转发状态、打标签、移动分组或删除。
常用选择方式:
Shift 点击另一个账号或选择框,会选中两者之间的连续范围。选中至少一个账号后,会出现批量菜单:
普通邮箱账号支持的批量操作:
临时邮箱分组也使用同一套选择方式,但批量菜单只显示适用于临时邮箱的操作,例如复制邮箱、标签添加/移除和删除;刷新 Token、转发开关、移动分组等普通账号专属操作会隐藏。
按分组导出时会包含所选分组及其所有子分组账号;如果同时选中了父分组和子分组,导出内容会自动去重。
「Token刷新管理」里的邮箱列表也支持同一套批量选择方式:
Shift 连续范围选择或拖拽选择账号。选中账号后可直接执行这些批量动作:
普通邮箱的邮件列表左侧也有选择框,适合批量处理当前邮箱的邮件:
邮件批量选择只作用于当前邮箱当前文件夹/聚合视图里已经加载的邮件;切换邮箱、刷新邮件列表或列表为空时,已选邮件会被清空。
适合这些场景:
user+tag@example.com邮件转发分成两层控制:
补充说明:
在「设置 -> WebDAV 备份」中配置:
https://dav.example.com/backups0 3 * * *补充说明:
all_groups_backup_YYYYMMDD_HHMMSS.txthttps://dav.jianguoyun.com/dav/mailBackup;不要只填写 https://dav.jianguoyun.com/dav仓库内置 Chrome / Edge Manifest V3 扩展,目录为 browser-extension/。扩展使用 Web 端登录密码,不需要对外 API Key。
安装方式:
chrome://extensions/ 或 edge://extensions/browser-extension 目录使用方式:
扩展会在浏览器侧边栏内提供原生操作面板,当前网页标签不会被切走。现在可直接使用邮箱、导入、刷新、Token、导出、标签和设置等功能。完整安装、配置、功能和故障排查说明见 浏览器扩展使用说明。
通过 API Key 直接获取邮件,无需登录 Web 界面。
当前额外支持:
folder=all 一次聚合收件箱和垃圾邮件并按标准化后的邮件时间倒序排序,top 按每个文件夹分别计算user+alias@example.com@gmail.com / @googlemail.com 地址时,原后缀未命中会自动回退到另一个后缀top=1skip / top 会做安全解析:非数字使用默认值,负数按 0 处理;top 最大 50配置步骤:
调用示例:
curl -H "X-API-Key: your-api-key" \
"http://localhost:5000/api/external/emails?email=user@outlook.com&folder=inbox"
curl -H "X-API-Key: your-api-key" \
"http://localhost:5000/api/external/emails?email=alias@example.com&folder=all&top=10"
curl -H "X-API-Key: your-api-key" \
"http://localhost:5000/api/external/emails?email=alias@example.com&folder=all&top=10&subject_contains=verify&from_contains=github&keyword=reset"
curl -H "X-API-Key: your-api-key" \
"http://localhost:5000/api/external/emails?email=user%2Balias%40example.com"
如果邮箱或别名里带特殊字符:
@ 可以直接传+ 建议编码成 %2B& 必须编码成 %26如果你把外部邮箱 B 自动转发到本项目管理的邮箱 A,再把 B 配成 A 的别名,那么后续可以直接用 B 作为 email 参数调用对外 API。
详细文档见 API 文档。
| 文档 | 说明 |
|---|---|
| 🚀 部署指南 | Docker、Docker Compose、Nginx/Caddy 部署、环境变量配置 |
| ⬆️ 升级指南 | Windows、Docker、Python 直跑升级与回滚建议 |
| 🔐 安全配置 | XSS/CSRF 防护、数据加密、速率限制、审计日志 |
| 🎭 外观皮肤 | 系统级皮肤、zip 上传、Git 仓库来源、皮肤包格式与持久化说明 |
| 📡 API 文档 | 对外简易API、完整API、代理配置 |
| 🛠️ 故障排查 | 常见问题、故障排查步骤 |
| 📋 更新日志 | 版本更新历史 |
| 🚢 发版说明 | 标准发版步骤、版本号规则、GitHub Release 说明 |
| 🛡️ 分支保护建议 | main/dev 使用边界、保护规则与构建触发建议 |
flask>=3.0.0
flask-wtf>=1.2.0 # CSRF 防护(推荐安装)
werkzeug>=3.0.0
requests[socks]>=2.25.0 # HTTP 请求与代理支持
APScheduler>=3.10.0 # 定时任务
croniter>=1.3.0 # Cron 表达式解析
bcrypt>=4.0.0 # 密码哈希
cryptography>=41.0.0 # 数据加密
开启2fa,然后在这里创建应用密码
https://support.google.com/mail/answer/185833?hl=zh-Hans
在 Telegram 搜索框搜索 @userinfobot 或 @getmyid_bot。
点击 Start。
机器人会立即回复你的 User ID(一串数字)。
如果你想知道别人的 ID:只需将对方发给你的消息转发给这个机器人,它就会显示该用户的 ID。
将上述机器人(如 @getmyid_bot)拉进你的群组。
在群组里输入 /myid(或者机器人指定的指令)。
机器人会返回该群组的 ID。
注意: 普通群组 ID 通常以数字开头,而**超级群组(Supergroup)或频道(Channel)**的 ID 通常以 -100 开头。
欢迎提交 Issue 和 Pull Request!
git clone https://github.com/assast/outlookEmail.git
cd outlookEmail
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python web_outlook_app.py
MIT License - 详见 LICENSE
本项目已在 LINUX DO 社区 发布,感谢社区的支持与反馈。
⭐ 如果这个项目对你有帮助,请给个 Star 支持一下!你的 Star 是我持续更新的动力! ⭐
初次维护一个项目,2026年04月11日15:45:33才发现有几个pull没合并,非常抱歉,这是我的联系方式如果我没看到的话,可以提醒我一下,有好的建议也可以提,感谢~ 邮箱:u3794336@outlook.com
本项目仅供学习、研究和技术交流使用,请遵守相关平台和服务条款,不要用于违规、滥用或非法用途。 因使用本项目产生的任何风险和后果,由使用者自行承担。