BACKEND / MAIL / CONFIGURATION GUIDE

腾讯企业邮箱
完整配置指南

从后台权限到第一封测试邮件,逐步配置 Foxmail、Outlook 与 Java 应用。遇到 535 时,沿着连接、加密、认证、投递四个阶段定位问题。

SMTP 465 · IMAP 993 · POP3 995适用:腾讯企业邮箱 / 企业微信邮件
CLIENT PASSWORDJAVAMAIL / JAKARTA MAILSPRING BOOT535 TROUBLESHOOTING
展开阅读目录

结论先行

先确认管理员允许客户端访问、成员启用对应协议;开启安全登录后,使用客户端专用密码;最后填写完整邮箱地址与 SSL/TLS 服务器参数。发送采用 smtp.exmail.qq.com:465,常规多端收信采用 imap.exmail.qq.com:993。

企业微信现行官方说明列出了上述 SSL 参数,并明确海外也使用通用服务器,无需添加 hw 前缀。客户端界面虽然可能显示“SSL”,实际加密协议由客户端与服务器协商;不要为了排障切换到明文连接。参见企业微信官方参数与 FAQ。

535 Authentication failed 不能单独证明“把登录密码当成了专用密码”。它表明认证未通过,用户名错误、凭据失效或访问策略也需要排查。JavaMail 的异常说明同样把用户名或密码错误列为认证失败示例。参见 API 说明。

问题背景:网页能登录,为什么程序不能发信?

网页登录、扫码登录与邮件协议登录属于不同入口。网页能正常打开,只能证明网页端登录成功,不能证明该成员已经获准通过 SMTP、IMAP 或 POP3 访问。以 server@sparrowzoo.com 为例,Java 程序发信需要 SMTP;Foxmail 或 Outlook 同时收发邮件通常需要 IMAP + SMTP。

先选协议,再检查对应权限
协议负责什么适用场景容易混淆的地方
SMTP提交待发送邮件Java 服务通知、客户端发信SMTP 成功不代表 IMAP 可用。
IMAP访问和同步服务器邮件电脑、手机、网页多端使用删除等操作可能同步到服务器,先理解客户端行为。
POP3将邮件下载到客户端明确需要本地下载的旧系统是否保留服务器副本取决于客户端设置;不能假设永远保留。

本文处理已有企业邮箱账号的客户端接入。域名开通、MX 迁移和域名级投递认证应按企业邮箱管理后台单独配置;调整这些 DNS 记录不能直接修复 SMTP 的 535 认证失败。本文中的账号仅用于说明,未对该账号的后台状态作实测判断。

按顺序完成四个环节,每一步都有独立验收点
01 / PERMISSION确认访问权限

管理员服务范围
成员协议开关

02 / CREDENTIAL生成有效凭据

安全登录状态
客户端专用密码

03 / CONNECTION配置加密连接

完整邮箱地址
正确服务器与端口

04 / DELIVERY验证实际收发

认证通过
测试邮件到达

详细配置:从权限到程序接入

1. 管理员与成员,两侧分别确认

1.1 管理员:把成员加入协议服务范围

  1. 由有邮件管理权限的管理员登录企业微信管理端。
  2. 在相应版本的后台进入 协作 → 邮件 → 安全管理 → 客户端访问权限。
  3. 查看 IMAP/SMTP 或 POP/SMTP 的服务范围,确认 server@sparrowzoo.com 对应成员或其所在组织在范围内。
  4. 保存配置,检查是否同时存在客户端类型、IP 或账号状态方面的限制。

1.2 成员:启用需要的协议组合

  1. 在电脑浏览器登录自己的企业邮箱。
  2. 进入 设置 → 收发信设置 → 开启服务。
  3. 常规收发勾选 开启 IMAP/SMTP 服务;旧系统要求 POP3 时选择 开启 POP/SMTP 服务。
  4. 点击 保存更改,重新进入页面,确认状态已保存。

菜单会随邮箱版本、管理入口及企业策略变化。上述为常见路径;找不到入口时,由管理员在当前后台搜索“客户端访问权限”或“协议服务”。开关灰色或无法保存,优先核对管理员服务范围和当前账号状态,不能仅凭界面现象断定唯一原因。

只需要程序发信时,Java 代码只配置 SMTP 即可;后台如果以 IMAP/SMTP 或 POP/SMTP 组合提供开关,仍需按后台实际支持的组合授权。无需为了 SMTP 发信在程序中建立 IMAP 连接。

两侧开关及路径依据:企业微信 · 常用邮件客户端软件 POP/IMAP/EXCHANGE 协议设置。

2. 客户端专用密码:与网页登录密码分清

在启用安全登录的账号中,第三方客户端使用的是客户端专用密码,也常被称作客户端授权码。企业微信扫码凭证、手机验证码、网页登录密码不能直接替代它。

2.1 生成步骤

  1. 电脑网页版登录邮箱,进入 设置 → 邮箱绑定;部分界面可能使用“微信绑定”或安全相关标签。
  2. 按页面要求完成身份绑定与验证,并确认 安全登录 已开启。
  3. 在 客户端专用密码 区域选择 生成新密码。
  4. 如果支持名称,使用便于识别的名称,例如 sparrow-notification-prod 或 office-foxmail。
  5. 生成后立即保存到受控的密码或密钥管理位置,填入客户端的“密码”字段;不要期待以后能再次查看原文。
凭据或状态如何使用需要注意
网页登录密码用于支持账号密码的网页入口安全登录开启后,不能作为第三方客户端的替代密码。
客户端专用密码填入 SMTP / IMAP / POP3 的密码字段必须属于正在认证的那个完整邮箱账号。
安全登录未开启以当前企业策略和页面说明为准部分账号可能允许登录密码;不要写成所有企业一律允许或一律禁止。
生成入口缺失检查绑定、安全登录、企业策略与账号类型不能直接认定只缺“绑定微信”这一个条件。

2.2 失效、更新与保存

  • 停用某个专用密码后,该密码立即失效;关闭安全登录后,所有已生成的专用密码都会失效。不要把关闭安全登录当作排障手段。
  • 更换密码后,同步更新应用的密钥配置和所有运行实例;仅修改本地配置文件,不会自动改变已启动进程中的配置。
  • 检查复制时是否夹带空格、换行或引号;按生成结果准确保存,不要在业务代码中随意改写密码。
  • 为不同应用分别生成凭据(若后台支持),便于独立撤销。密码不写入 Java 源码、Git、文章截图或公开日志。

生成路径与失效规则依据:企业微信 · 邮箱绑定微信与获取客户端专用密码。生成后立即保存是操作建议;本文不把“只显示一次”作为已核验的官方规则。

3. 服务器参数,一次填对

现行官方 SSL 参数;通用服务器同样适用于海外,信创地址仅用于已启用信创邮箱的企业
服务通用服务器(含海外)信创邮箱服务器端口加密
SMTP 发信smtp.exmail.qq.comxcsmtp.exmail.qq.com465SSL/TLS
IMAP 收信imap.exmail.qq.comxcimap.exmail.qq.com993SSL/TLS
POP3 收信pop.exmail.qq.comxcpop.exmail.qq.com995SSL/TLS

参数来源:企业微信现行官方设置说明。先确认企业是否启用信创邮箱;启用时应使用相应 xc 主机,且不支持 Exchange。旧版腾讯云指南曾列出 hwsmtp / hwimap / hwpop;现行 FAQ 已明确海外无需加 hw,本文不将旧地址作为默认方案。

  • 用户名:完整邮箱地址,如 server@sparrowzoo.com,不是 server、显示姓名或企业微信用户 ID。
  • 密码:安全登录场景下填写该成员生成的客户端专用密码。
  • 发信认证:启用“SMTP 服务器需要身份验证”;基线配置中收发信使用同一账号与有效凭据。
  • 服务器类型:不要把腾讯企业邮箱的 *.exmail.qq.com 与个人 QQ 邮箱的服务器混用。

465 的 SSL/TLS 与 STARTTLS 有什么区别?

本指南使用 465 的隐式 TLS:连接建立后直接进行 TLS 握手,对应 mail.smtp.ssl.enable=true。STARTTLS 则是在另一种连接模式中通过 SMTP 命令升级加密,不是将 465 上的 SSL 开关换一个名字。本文不把 587 当作已核验的腾讯企业邮箱推荐参数。

示例统一使用 smtp 协议配合 mail.smtp.* 属性。如果你改用 smtps,必须检查实现要求的 mail.smtps.* 属性前缀,避免端口、认证和超时配置没有生效。参见 JavaMail SMTP 属性说明。

4. Foxmail、Outlook 与其他客户端

客户端版本和操作系统不同,按钮名称会变化。下面以手动配置 IMAP + SMTP为统一核对方式;如果自动识别失败,手动填写服务器与端口。

4.1 Foxmail

  1. 新建账号,选择腾讯企业邮箱或手动配置入口。
  2. 使用账号密码方式时,输入完整邮箱地址及客户端专用密码;若当前版本提供企业邮箱扫码登录,可按其引导操作。
  3. 收信类型选择 IMAP:服务器 imap.exmail.qq.com,端口 993,开启 SSL/TLS。
  4. 发信服务器 smtp.exmail.qq.com,端口 465,开启 SSL/TLS 和身份验证。
  5. 保存后分别验证收信和发信,不要只看账号添加成功的提示。

4.2 Outlook

  1. 添加账户,选择高级设置、手动设置或 IMAP 入口(具体名称依版本而定)。
  2. 收信服务器和发信服务器分别填写上述 IMAP、SMTP 参数。
  3. 在提供相关选项的经典版本中,勾选“发送服务器需要验证”,使用与接收服务器相同的账号凭据。
  4. 高级设置中核对 IMAP 993、SMTP 465,加密选择 SSL/TLS。
  5. 测试收发。若版本不提供这些字段,使用该版本的手动 IMAP 指引,不照搬其他版本截图。

4.3 手机邮箱或 POP3 客户端

支持手动 IMAP/SMTP 的手机邮件应用使用同一组参数。确需 POP3 时,将收信改为 pop.exmail.qq.com:995,同时开启对应 POP/SMTP 权限;发信仍为 SMTP 465。第一次同步前,核对“保留服务器邮件副本”和删除策略,避免误把下载当成多端同步。

官方示例可参考腾讯云操作指南中的 Foxmail、Outlook 与移动客户端设置;本文按通用字段重组步骤,当前客户端界面优先。

5. JavaMail / Jakarta Mail:完整发送示例

5.1 先确认依赖属于哪个命名空间

下面代码使用 javax.mail,适用于已有 JavaMail 1.6.x API 的项目。采用 Jakarta Mail 2.x 的项目,应将全部 javax.mail 导入改为 jakarta.mail,并使用相匹配的运行时实现,例如 Eclipse Angus Mail。不要只加入 API 包后遗漏 SMTP 实现,也不要同时混用两套命名空间。Spring Boot 项目优先使用下一节的 starter 和项目自身的版本管理。

运行前,在应用实际启动环境中配置以下变量。本文不提供真实密码;环境变量也应通过受控部署配置注入,避免把密钥写进命令历史。

变量值或用途是否必需
MAIL_USERNAME完整邮箱地址,例如 server@sparrowzoo.com是
MAIL_CLIENT_PASSWORD该账号生成的客户端专用密码是
MAIL_TEST_TO由你控制、用于验收的收件邮箱发送测试邮件时需要

ExmailSmtpExample.java · 运行后发送一封测试邮件

import java.util.Date;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public final class ExmailSmtpExample {
    private static String requiredEnv(String name) {
        String value = System.getenv(name);
        if (value == null || value.trim().isEmpty()) {
            throw new IllegalArgumentException("Missing environment variable: " + name);
        }
        return value; // 原样使用凭据,不修改密码内容
    }

    public static void main(String[] args) throws Exception {
        String username = requiredEnv("MAIL_USERNAME");
        String password = requiredEnv("MAIL_CLIENT_PASSWORD");
        String recipient = requiredEnv("MAIL_TEST_TO");

        Properties props = new Properties();
        props.setProperty("mail.smtp.host", "smtp.exmail.qq.com");
        props.setProperty("mail.smtp.port", "465");
        props.setProperty("mail.smtp.auth", "true");
        props.setProperty("mail.smtp.ssl.enable", "true");
        props.setProperty("mail.smtp.ssl.checkserveridentity", "true");
        props.setProperty("mail.smtp.starttls.enable", "false");
        props.setProperty("mail.smtp.connectiontimeout", "10000");
        props.setProperty("mail.smtp.timeout", "10000");
        props.setProperty("mail.smtp.writetimeout", "10000");
        props.setProperty("mail.debug.auth", "false");

        Session session = Session.getInstance(props);
        session.setDebug(false);

        MimeMessage message = new MimeMessage(session);
        message.setFrom(new InternetAddress(username));
        message.setRecipient(Message.RecipientType.TO,
                new InternetAddress(recipient, true));
        message.setSubject("腾讯企业邮箱 SMTP 配置测试", "UTF-8");
        message.setText("如果收到此邮件,说明本次 SMTP 提交与投递链路已完成。", "UTF-8");
        message.setSentDate(new Date());

        Transport.send(message, username, password);
        System.out.println("SMTP submission completed; check the recipient inbox.");
    }
}

示例发件人 From 与认证账号一致,便于先建立可工作的基线。需要别名或代表其他地址发信时,先确认相应的代发权限。超时单位为毫秒,10000 是示例值,可按网络环境调整。不要设置 mail.smtp.ssl.trust=* 或关闭证书校验来“解决”TLS 错误。

属性依据:SMTP provider 配置;发送方法依据:Transport.send API。正常返回表示提交成功,最终是否到达收件箱仍需收件端确认。

5.2 只验证 SMTP 登录,不发送邮件

排查认证时,可在上例创建 session 后,以以下代码替换创建消息及发送部分;同时去掉读取 MAIL_TEST_TO 的那一行。这样可以将“认证成功”与“投递成功”分开验证。

try (Transport transport = session.getTransport("smtp")) {
    transport.connect("smtp.exmail.qq.com", 465, username, password);
    System.out.println("SMTP authentication succeeded.");
}

5.3 如果程序还需要 IMAP 收信

收信另建一个 Store;以下片段复用前面的 username、password,并额外导入 javax.mail.Store(Jakarta 项目使用对应包)。它只验证连接,不读取或删除邮件。

Properties imapProps = new Properties();
imapProps.setProperty("mail.imap.ssl.enable", "true");
imapProps.setProperty("mail.imap.ssl.checkserveridentity", "true");
imapProps.setProperty("mail.imap.connectiontimeout", "10000");
imapProps.setProperty("mail.imap.timeout", "10000");
Session imapSession = Session.getInstance(imapProps);

try (Store store = imapSession.getStore("imap")) {
    store.connect("imap.exmail.qq.com", 993, username, password);
    System.out.println("IMAP authentication succeeded.");
}

6. Spring Boot:交给 JavaMailSender 管理

在已经使用 Spring Boot parent 或 BOM 管理依赖版本的项目中,加入 mail starter;版本沿用当前项目,避免另引入一套不兼容的邮件实现。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

application.yml · 密码来自运行环境

spring:
  mail:
    host: smtp.exmail.qq.com
    port: 465
    protocol: smtp
    username: ${MAIL_USERNAME}
    password: ${MAIL_CLIENT_PASSWORD}
    default-encoding: UTF-8
    properties:
      "[mail.smtp.auth]": true
      "[mail.smtp.ssl.enable]": true
      "[mail.smtp.ssl.checkserveridentity]": true
      "[mail.smtp.starttls.enable]": false
      "[mail.smtp.connectiontimeout]": 10000
      "[mail.smtp.timeout]": 10000
      "[mail.smtp.writetimeout]": 10000
      "[mail.debug.auth]": false

方括号包围的键会作为完整 JavaMail 属性名传递。Spring Boot 官方特别提醒,部分邮件超时默认可能为无限等待,因此建议显式设置。若项目配置了 spring.mail.jndi-name,JNDI Session 会优先于其他 Session 设置,排查时也要确认是否存在自定义 JavaMailSender 覆盖自动配置。参见 Spring Boot Sending Email。

ExmailTestService.java · 在需要测试时显式调用

import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

@Service
public class ExmailTestService {
    private final JavaMailSender sender;
    private final String from;

    public ExmailTestService(JavaMailSender sender,
                            @Value("${spring.mail.username}") String from) {
        this.sender = sender;
        this.from = from;
    }

    public void sendTest(String recipient) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(recipient);
        message.setSubject("腾讯企业邮箱配置测试");
        message.setText("请确认这封测试邮件已到达收件箱。");
        sender.send(message);
    }
}

将 recipient 设为你控制的测试邮箱,再由测试入口调用该方法;不要把示例直接做成无需鉴权、可任意指定收件人的公开接口。部署后还要确认实际启用的 profile、容器或服务进程已读取新的配置。

排查流程:先定位失败发生在哪一层

固定同一个账号、服务器和运行环境,每次只调整一个因素。先保存脱敏后的完整错误信息,包括 SMTP 返回码、失败阶段和发生时间;只提供“发送失败”四个字无法区分网络、认证与投递问题。

7. DNS、TCP 与 TLS:先验证连接

以下命令应在真正运行 Java 服务的机器或容器网络环境中执行。Mac 本机能连通,不代表部署服务器也能连通。命令只检查解析、端口或 TLS,不执行账号认证,也不发送邮件。

# macOS / Linux;需要安装对应工具
nslookup smtp.exmail.qq.com
nc -vz -w 5 smtp.exmail.qq.com 465

# 需要收信时再检查 IMAP
nc -vz -w 5 imap.exmail.qq.com 993
# Windows PowerShell
Resolve-DnsName smtp.exmail.qq.com
Test-NetConnection smtp.exmail.qq.com -Port 465

端口不通,检查 DNS、防火墙、云出口策略、容器网络或代理路径。不要只用 ping 判断邮件端口是否可用。

# OpenSSL 1.1.1+ / 3.x;检查 TLS 与服务端身份
openssl s_client -connect smtp.exmail.qq.com:465 \
  -servername smtp.exmail.qq.com \
  -verify_hostname smtp.exmail.qq.com \
  -verify_return_error -crlf

正常情况下可以看到 TLS 协商信息、证书校验通过,以及 SMTP 的 220 问候;输入 QUIT 退出。工具版本、系统 CA 路径不同可能导致额外配置需求。即使这里成功,Java 的 truststore 或 JDK 环境仍可能不同,必须结合 Java 的异常继续检查。不要在终端手工粘贴密码执行 AUTH。

8. 535 认证失败:按这个顺序检查

  1. 确认真实账号:认证用户名是否是完整邮箱地址,是否误用了显示名、别名或其他成员生成的密码。
  2. 确认密码类型与状态:安全登录开启时使用专用密码;无法确认凭据有效性时,在后台重新生成并更新受控配置。
  3. 确认两级权限:管理员服务范围包含该成员,成员协议开关已保存。
  4. 确认程序生效配置:排除旧环境变量、错误 profile、自定义 Session / Sender、旧进程或某个实例尚未重启。
  5. 确认账号与访问策略:让管理员核对账号停用、风险限制、客户端限制和适用的 IP 访问策略;以完整服务端返回为准。
  6. 最小化对照:在同一网络使用客户端或本节认证探针验证;若只有应用失败,重点对比它实际加载的配置与依赖。

RFC 4954 将 535 5.7.8 定义为认证凭据无效或不足。它不是“网页登录密码被误用”的专属错误码。没有完整返回信息和后台检查结果时,应写“可能原因”,不能写“已确定直接原因”。参见 RFC 4954 §6。

9. 常见现象与下一步动作

现象 / 日志优先检查下一步
UnknownHostException域名拼写、DNS、运行环境解析在实际服务器解析域名,不先重置密码。
连接超时 / Connection refused出站网络、端口、路由及防火墙检测 465 / 993;区分连接阶段超时与读写阶段超时。
SSLHandshakeException / PKIXJDK 信任库、证书链、系统时间、TLS 拦截检查证书与运行环境;不要关闭校验或信任所有主机。
535 / AuthenticationFailedException用户名、专用密码、权限和账号策略按上方六步逐项核对,保留脱敏后的服务端原文。
无法勾选协议服务管理员服务范围、当前账号和页面权限由管理员核对授权;保存后重新登录检查。
没有生成密码按钮账号绑定、安全登录及企业策略检查当前版本的绑定 / 安全设置,不照搬旧界面。
之前能用,突然失效凭据撤销、安全登录变化、账号策略及部署变更对照变更时间;必要时生成新凭据并同步各实例。
终端启动正常,supervisord 启动后读不到环境变量systemd 服务环境与应用变量名是否一致在 supervisord 的 service 中配置 Environment=,重新加载 unit 并重启服务,详见环境变量不生效。
明确提示 IP 不在允许范围企业是否启用适用的 IP 访问限制由管理员核对服务器实际公网出口 IP;容器私网 IP 不能替代公网出口。
能收不能发SMTP 主机、465、TLS、发信认证单独测试 SMTP,不能用 IMAP 登录成功代替发信验证。
能发不能收IMAP / POP 权限、收信主机与端口按实际协议分别检查 993 或 995。
认证成功,但 550 / 553 等被拒完整错误文本、发件人权限、收件地址、投递策略先确定拒绝发生在 MAIL FROM、RCPT TO 还是 DATA;错误码不与单一原因绑定。
只收到近 30 天邮件 / 文件夹不同步收取时间范围、自定义文件夹与文件夹锁设置在网页版收发信设置核对收取范围及“收取我的文件夹”;已发送不同步时检查“保存已发送至服务器”。官方 FAQ
程序提示成功,收件人未收到延迟、退信、垃圾箱、隔离区、收件方策略查看消息 ID、退信和管理后台日志;提交成功不等于最终送达。
NoSuchProviderException / 类缺失是否只有 API、是否混用了 javax / jakarta检查依赖树及运行时邮件实现,不先修改服务器参数。

诊断日志应该保留什么?

可临时设置 session.setDebug(true),并保持 mail.debug.auth=false;Spring Boot 可临时添加 spring.mail.properties[mail.debug]=true。即使关闭认证调试,日志仍可能包含地址、主机和会话信息,分享前要脱敏,排障后关闭。

提交给管理员的信息应包括:发生时间与时区、脱敏账号、源环境与出口 IP、主机和端口、使用的 TLS 模式、JDK / 邮件库版本、完整错误码及失败阶段。不要附带专用密码或完整邮件正文。

10. 常见问题:supervisord 启动后环境变量不生效

现象:终端中手动启动 Java 程序可以读取密码,通过 systemd 启动 supervisord 后,程序读不到 email_password 等变量,或仍使用旧值。

原因:systemd 管理的系统服务不会自动继承当前终端的 export,也不会自动加载该用户的 .bashrc、.bash_profile。环境应沿着 systemd → supervisord → Java 子进程传递。Supervisor 会继承启动环境,其全局或 [program:x] 中的 environment= 还可能覆盖同名值。参见 Supervisor 环境继承说明。

10.1 在 systemd 服务中声明变量

/usr/lib/systemd/system/supervisord.service 通常是安装包提供的原始文件;本机自定义完整 unit 放在 /etc/systemd/system/supervisord.service,同名文件优先。无需同时修改两处。先确认当前加载的文件及附加配置:

sudo systemctl show supervisord.service -p FragmentPath -p DropInPaths

# 查看安装包提供的原始配置
sudo vi /usr/lib/systemd/system/supervisord.service

# 编辑本机自定义配置;若文件不存在,先从原始 unit 复制并保留必要设置
sudo vi /etc/systemd/system/supervisord.service

以下沿用当前部署的路径与 Type=forking,关键是 [Service] 内的 Environment=。已有 unit 应保留原有 PIDFile、停止方式、用户和其他必要设置;如果只需追加变量,也可以执行 sudo systemctl edit supervisord.service,在 drop-in 中仅填写 [Service] 与 Environment=。

[Unit]
Description=Process Monitoring and Control Daemon
After=rc-local.service

[Service]
Type=forking
ExecStart=/usr/bin/supervisord -c /root/supervisord/supervisord.conf
RuntimeDirectory=supervisor
RuntimeDirectoryMode=755
Environment="authenticator_encrypt_key=111111" "email_password=111111" "mysql_sparrow_password=111111"

[Install]
WantedBy=multi-user.target

After=rc-local.service 只声明启动顺序,不会继承 rc.local 中导出的变量。RuntimeDirectory=supervisor 只负责创建运行目录,PID 文件和 socket 路径仍由 supervisord 配置决定;使用 PIDFile= 时须与 supervisord 的 pidfile 路径一致。

111111 全部为占位值,部署时替换;其中 email_password 应填写邮箱客户端专用密码。unit 中的 Environment= 是明文配置,实际密钥应使用受限的部署配置管理,不提交到公开仓库。Type=forking 要求 supervisord 以后台模式启动;若原服务使用 -n 或 nodaemon=true,保留匹配的前台服务类型,不要直接套用这里的 forking 设置。

10.2 变量名必须与程序读取方式一致

环境变量名区分大小写。当前部署使用 email_password,而本文前面的示例读取 MAIL_CLIENT_PASSWORD,两者不会自动对应。沿用当前部署变量名时,Java 读取改为 System.getenv("email_password");Spring Boot 配置改为:

spring:
  mail:
    password: ${email_password}

上面的 YAML 只替换原配置中的 password 字段,其他 SMTP 参数和用户名配置保持完整。也可以保留原代码,在 service 中直接声明 MAIL_CLIENT_PASSWORD。不要写成 Environment=MAIL_CLIENT_PASSWORD=$email_password,systemd 的这个字段不进行 shell 变量展开。

10.3 重新加载 unit,再重启 supervisord

仅保存文件、执行 source、supervisorctl reread/update 或仅重启受管程序,都不能让已运行的 supervisord 获得新的 systemd 环境。需要让 systemd 重新读取 unit,再重新创建 supervisord 及其子进程:

sudo systemctl daemon-reload
sudo systemctl restart supervisord.service
sudo systemctl status supervisord.service --no-pager
sudo supervisorctl -c /root/supervisord/supervisord.conf status

重启 supervisord 会影响它管理的程序,应在可接受的重启窗口执行。检查各程序是否重新进入 RUNNING;未配置自动启动的程序需按实际服务名启动。daemon-reload 只加载配置,不会单独改变正在运行的进程环境。

10.4 在目标 Java 进程验证,避免只检查终端

在实际受 supervisord 管理的应用中临时检查变量是否存在,输出布尔值即可;终端执行 echo 得到的值不能证明服务进程已经收到配置。

String emailPassword = System.getenv("email_password");
System.out.println("email_password configured: "
        + (emailPassword != null && !emailPassword.trim().isEmpty()));

确认变量已传入后,再做 SMTP 认证测试。若仍读到旧值,核对是否连到了另一套 supervisord 实例、是否存在同名 environment= 覆盖,以及业务程序是否真正重启。

验收与日常维护

按下面顺序验收,避免只看到“已连接”就认为配置全部完成。

  1. 权限:记录管理员服务范围与成员协议开关的检查结果。
  2. 认证:在实际部署环境完成 SMTP 登录;需要收信时另验 IMAP 或 POP3。
  3. 投递:给可控邮箱发送一封带时间标识的测试邮件,确认收件箱或垃圾箱中的实际到达情况;必要时同时验证企业内和企业外收件地址。
  4. 收信:使用客户端刷新收件箱,确认邮件可读;IMAP 场景再检查已读状态同步是否符合预期。
  5. 持久化:重启应用或客户端后复测,确认配置与密钥没有只存在于临时会话。
  6. 维护:记录凭据用途和责任人;轮换时先部署并验证新凭据,再按管理策略撤销旧凭据。

生产通知应设置合理超时、失败告警和有界重试。认证失败时不要高频重试;在提交结果不明确的超时场景下,重试可能导致重复邮件,应使用业务消息标识辅助去重。批量发送能力与额度以企业实际套餐和后台策略为准,本文不假定固定限额。

总结:权限、凭据、连接、投递逐层确认

管理员允许访问 + 成员启用协议 + 使用当前策略要求的有效凭据 + 正确的 SSL/TLS 参数,构成客户端配置的基础。开启安全登录时,凭据就是客户端专用密码。

遇到 535,优先核对完整账号、专用密码和两级权限,再看运行配置与安全策略;连接超时先查网络,TLS 异常先查证书,认证成功后的退信再查投递。每一步都用对应的检查结果验证,直到测试邮件真实到达。

从权限检查开始

官方资料与适用边界

本指南整理于 2026 年 9 月 26 日。服务器参数参考腾讯官方资料;管理菜单、绑定方式、密码生命周期及企业策略以当前账号后台为准。以下示例为接入方法,不表示已经对示例账号进行真实登录或发送测试。

  1. 企业微信 · 常用邮件客户端软件 POP/IMAP/EXCHANGE 协议设置:两级权限、通用与信创参数、海外无需 hw 前缀及客户端常见问题。
  2. 企业微信 · 邮箱绑定微信与获取客户端专用密码:生成路径、安全登录及密码失效规则。
  3. 腾讯云 · 腾讯企业邮操作指南(旧版 PDF):历史参数及客户端示例;海外 hw 主机说明与现行帮助不同,以现行帮助为准。
  4. JavaMail · SMTP provider 属性:认证、SSL、STARTTLS、超时和属性前缀。
  5. JavaMail FAQ:SSL 配置、依赖和常见接入问题。
  6. JavaMail · Transport API:带用户名和密码的发送方法,以及提交成功与最终送达的区别。
  7. JavaMail · AuthenticationFailedException:认证失败异常语义。
  8. Spring Boot · Sending Email:mail starter、自动配置、超时和 JNDI Session 优先级。
  9. RFC 4954 · SMTP Authentication:535 等认证响应码的标准语义。
  10. systemd.exec · Environment、systemctl:服务环境配置、daemon-reload 与重启。
  11. Supervisor · Subprocess Environment:子进程环境继承与 environment 配置覆盖关系。