Rails7使用mail_form+SendGrid时联系表单发送成功但收不到邮件
问题核心原因
SendGrid作为第三方邮件代发平台,反垃圾校验规则远严于个人邮箱SMTP服务,你遇到的「日志显示发送成功但收不到、Devise邮件正常」问题,本质是联系表单邮件触发了SendGrid的静默丢弃规则,没有真的投递到收件邮箱:
- Devise邮件能正常送达,是因为Devise发信时固定使用你配置的认证发件人地址,头信息完全合规
- 你当前联系表单的配置有三个高风险点:
from和to填了完全相同的邮箱地址、使用hotmail这类公共邮箱作为代发发件人、mail_form默认自动把用户填写的第三方邮箱加为Reply-To头(这个头你本地日志没打全,所以没看到),这三个特征组合起来会被SendGrid判定为伪造欺诈邮件,直接拦截丢弃,不会返回错误响应,所以本地日志会显示发送成功。
Gmail SMTP没出现这个问题,是因为你是用自己的账号密码登录Gmail服务器发信,平台默认信任账号持有者的操作,不会做这类严格拦截。
排查步骤(按优先级来)
- 先查SendGrid后台的「Email Activity」(邮件活动)页面,按你测试发信的时间筛选,能直接看到SendGrid侧对这封邮件的处理结果:是拦截丢弃、反弹、还是进了垃圾池,这里会标注明确的拦截原因,比本地日志准确100%
- 对比Devise正常邮件和联系表单邮件的原始头:找一封能正常收到的Devise邮件,查看原始邮件信息,你会发现Devise邮件的
From、Return-Path都是你认证过的发件地址,而联系表单邮件会多出来一个非认证域的Reply-To地址 - 检查SMTP配置里的
domain字段:你当前配置里这个值取的是credentials里的域名,如果填的是hotmail.com这类公共邮箱域名,本身就不符合SendGrid的配置要求,SendGrid要求这个字段填你完成SPF/DKIM认证的自有域名。
修复方案
- 修正Contact模型的邮件头配置,不要用公共邮箱作为代发发件人,显式指定回复地址,避免from/to同地址:
# models/contact.rb def headers { subject: "网站联系表单消息: #{subject}", to: "ramonakim@hotmail.com", # 你的收件邮箱 from: "no-reply@你在SendGrid完成认证的自有域名.com", # 必须是SendGrid后台验证通过的发件人,不要用hotmail/gmail公共邮箱 reply_to: email # 显式把用户填的邮箱设为回复地址,收到邮件点回复就直接发给填表用户 } end
- 修正环境配置里的SMTP设置,用Rails标准配置方式,不要直接修改ActionMailer全局常量:
# config/environments/development.rb config.action_mailer.raise_delivery_errors = true config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } config.action_mailer.smtp_settings = { user_name: 'apikey', # 固定值就是字符串'apikey',不用改 password: Rails.application.credentials.sendgrid_secret_api, domain: '你在SendGrid认证的自有域名.com', # 和发件人邮箱后缀一致,确保已经配好SPF/DKIM记录 address: 'smtp.sendgrid.net', port: 587, authentication: :plain, enable_starttls_auto: true }
- 如果暂时没有自有域名,必须用公共邮箱发信:先在SendGrid后台完成对应公共邮箱的单邮箱发件验证,同时把
from地址改成另一个你自己的邮箱,不要和to的收件地址完全一致,避免触发同地址发收的反垃圾规则。 - 测试时不要用
somedude@example.com这类不存在的虚拟邮箱填表单,用真实可收信的邮箱测试,不存在的发件人域名也会触发反垃圾拦截。
内容的提问来源于stack exchange,提问作者v8soup
相关产品推荐
相关产品推荐

