sendgrid php库本身不保证可靠投递,仅负责发送请求至api;交易邮件需手动实现重试、队列与状态回写三重防护,并正确使用personalization和dynamictemplatedata避免收件人信息串扰。

sendgrid/sendgrid 库本身不保证“可靠投递”,它只负责把邮件请求发给 SendGrid API。真正影响交易类邮件是否送达的,是配置方式、错误处理逻辑和重试机制——这些都得你手动补上。
为什么直接调 $sendgrid->send() 会丢订单确认邮件
默认用法里,send() 是同步 HTTP 请求,网络抖动、API 限流、临时 503 响应都会导致抛出 Exception,而你 catch 之后如果只是 echo 或 log,那这封邮件就彻底没了。交易类邮件(比如支付成功通知、密码重置)必须做到“至少送达一次”,不能依赖单次请求。
常见错误现象:
-
SendGrid\Exception被静默吞掉,没重试也没落库 - 用
mail()或本地 SMTP 发交易邮件,被 Gmail/Outlook 直接归入垃圾箱 - 模板里硬编码收件人邮箱,没做
filter_var($email, FILTER_VALIDATE_EMAIL)校验,导致 400 错误失败但没感知
必须加的三步防护:重试 + 队列 + 状态回写
交易邮件不是“发出去就行”,而是“发出去且确认送达或可追溯”。光靠 sendgrid/sendgrid 的基础调用远远不够。
- 用
try/catch捕获SendGrid\Exception后,不要立即放弃,先记录到数据库(含$email内容、时间、错误码),再触发异步重试(例如通过 Redis +php-resque或 Laravel Queue) - 发送前检查
getenv('SENDGRID_API_KEY')是否为空,空则直接 fail-fast,避免走到send()才报错 - 在
$response->statusCode()返回 202 时才认为“已接受”,但注意:202 ≠ 已投递,只是 SendGrid 接收成功;需后续通过 Webhook 或 /messages 接口查投递状态
Personalization 用错会导致收件人串号
交易邮件常需一对一内容(如订单号、金额),但很多人误用 addTo() 多次,结果所有收件人都看到同一份内容。正确做法是每个收件人配一个 Personalization 实例。
错误写法:
$email->addTo('a@example.com');
$email->addTo('b@example.com'); // b 也会收到 a 的订单数据
正确写法:
$p1 = new Personalization();
$p1->addTo(new To('a@example.com'));
$p1->setDynamicTemplateData(['order_id' => 'ORD-001']);
$email->addPersonalization($p1);
<p>$p2 = new Personalization();
$p2->addTo(new To('b@example.com'));
$p2->setDynamicTemplateData(['order_id' => 'ORD-002']);
$email->addPersonalization($p2);
</p>
注意:setDynamicTemplateData() 只对当前 Personalization 生效,且模板里必须用 {{order_id}} 语法,不能用 %order_id% —— 后者是手写字符串替换,和 SendGrid 动态模板无关。
模板加载和变量注入别混用两种机制
有人一边用 SendGrid 动态模板(setTemplateId()),一边又用 str_replace() 替换 HTML 字符串,结果变量被替两次或漏替。必须明确路径:
- 走动态模板路线:上传模板到 SendGrid 控制台 → 用
setTemplateId('d-xxx')→ 用setDynamicTemplateData()传参 → 模板内用{{variable}} - 走静态模板路线:用
file_get_contents('template.html')→ 手动str_replace('{{name}}', $user_name, $html)→ 再塞进addContent('text/html', $html)
两者不能交叉。尤其注意:动态模板里 {{ }} 是 Handlebars 语法,不支持 PHP 表达式,比如 {{#if paid}}...{{/if}} 可以,但 {{ $amount * 1.1 }} 会原样输出。
SendGrid 的 API 响应快,但交易邮件的可靠性不在客户端库,而在你有没有为失败留退路、为并发留隔离、为追踪留标记。最常被忽略的点是:没把 Personalization 和 DynamicTemplateData 绑定到具体收件人实例,导致 A 的订单信息发给了 B。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











