Elixir Phoenix通过Amazon SES发邮件遇cacerts未定义问题求助
解决Elixir/Phoenix中使用Amazon SES发送邮件时的
cacerts: :undefined错误 底层原因
这个错误的核心是Erlang SSL模块在启用verify: :verify_peer时,无法找到有效的CA证书文件。开启对等验证后,SSL模块需要可信CA证书来验证服务器证书合法性,若指定的证书路径不存在、文件损坏,或配置选项冲突,就会返回cacerts: :undefined错误。
另外你的配置中同时设置ssl: true和tls: :always存在冲突:
ssl: true对应465端口的直接SSL连接tls: :always对应587端口的STARTTLS升级
同时开启会导致SSL模块配置混乱,加重证书加载问题。
解决方案
1. 确认CA证书路径有效性
虽然安装了ca-certificates,但不同环境的证书路径可能不同:
- Ubuntu/Debian:
/etc/ssl/certs/ca-certificates.crt - Alpine Linux:
/etc/ssl/cert.pem - RHEL/CentOS:
/etc/pki/tls/certs/ca-bundle.crt
用以下命令验证路径是否存在:
ls -l /etc/ssl/certs/ca-certificates.crt
若文件不存在,需确认证书包是否正确安装,或查找系统实际的CA证书路径。
2. 使用Erlang自带CA证书(推荐)
Elixir生态的certifi包提供预打包的可信CA证书,可避免依赖系统证书路径:
- 添加
certifi到mix.exs依赖:
defp deps do [ # 其他依赖 {:certifi, "~> 2.11"} ] end
- 运行
mix deps.get安装依赖 - 修改
config/prod.exs配置,用:certifi.cacertfile()获取证书路径:
config :my_app, MyApp.Mailer, adapter: Bamboo.SMTPAdapter, server: System.get_env("SES_SMTP_SERVER") || "email-smtp.us-east-1.amazonaws.com", port: String.to_integer(System.get_env("SES_SMTP_PORT") || "465"), username: System.get_env("SES_SMTP_USERNAME"), password: System.get_env("SES_SMTP_PASSWORD"), ssl: true, # 465端口用ssl: true,不要设置tls选项 retries: 1, ssl_options: [ verify: :verify_peer, cacertfile: :certifi.cacertfile() ]
3. 修正端口与加密选项的对应关系
- 若用465端口:设置
ssl: true,不要配置tls相关选项 - 若用587端口:设置
tls: :always、ssl: false,并将ssl_options改为tls_options:
config :my_app, MyApp.Mailer, adapter: Bamboo.SMTPAdapter, server: System.get_env("SES_SMTP_SERVER") || "email-smtp.us-east-1.amazonaws.com", port: String.to_integer(System.get_env("SES_SMTP_PORT") || "587"), username: System.get_env("SES_SMTP_USERNAME"), password: System.get_env("SES_SMTP_PASSWORD"), tls: :always, retries: 1, tls_options: [ verify: :verify_peer, cacertfile: :certifi.cacertfile() ]
生产环境成功配置示例(Amazon SES + Bamboo)
以下是经过验证的生产环境配置,使用certifi规避系统证书依赖:
# mix.exs 依赖 defp deps do [ {:bamboo, "~> 2.2"}, {:bamboo_smtp, "~> 4.2"}, {:certifi, "~> 2.11"} ] end # config/prod.exs config :my_app, MyApp.Mailer, adapter: Bamboo.SMTPAdapter, server: System.get_env("SES_SMTP_SERVER"), port: 465, username: System.get_env("SES_SMTP_USERNAME"), password: System.get_env("SES_SMTP_PASSWORD"), ssl: true, retries: 2, ssl_options: [ verify: :verify_peer, cacertfile: :certifi.cacertfile(), depth: 2 ]
内容的提问来源于stack exchange,提问作者legoblocks
相关产品推荐
相关产品推荐

