升级 Magento 2.4 后,订单邮件能发出,订单号也有,但旧模板里客户名、付款方式或自定义字段变成空白。很多旧模板直接调用对象方法,过去能工作不代表现在仍被允许。2.4 默认更严格地限制模板可执行内容,这是安全边界,不建议为了兼容旧写法把它关掉。

先把“邮件没数据”和“模板取不到”分开

临时切回当前版本自带的订单模板发送测试。如果默认模板正常,发送流程、订单对象和队列基本没问题;只需迁移自定义模板。若默认模板也缺值,再检查调用 Sender 时传入的 template vars。

在后台加载默认模板,查看页面列出的可用变量。新模板常使用已经整理好的变量,例如 order_data 中的 customer_name,而不是在模板里层层调用订单对象。

不要继续在模板里调用getData和任意方法

旧写法可能类似从 order 对象继续取 payment、address,再调用方法。严格模式下这些访问会被拦截或返回空。正确做法是在发送邮件的 PHP 代码里先把需要的数据整理为标量或安全对象,再作为命名变量传给模板。

$transport = [
    'order' => $order,
    'order_data' => [
        'customer_name' => $order->getCustomerName(),
        'custom_reference' => (string)$order->getData('custom_reference')
    ]
];

示例只说明思路。实际项目应尽量扩展现有 transport,而不是复制整个 Sender。自定义字段还要做合适的 HTML 转义;只有确实是可信 HTML 的内容才使用 raw。

队列会让你一直看到修改前的结果

异步发送开启时,测试邮件可能是队列里旧任务生成的。记录订单号、模板 ID 和入队时间,清楚地区分新订单与旧消息。也要确认配置作用域选中了你刚修改的模板,多商店经常仍引用另一份副本。

我最后会测试游客订单、注册客户、缺少自定义字段和包含特殊字符的客户名。模板不报错只是最低要求,还要保证空值有合理兜底、HTML 没被意外转义,并且不重新开放任意方法调用。这样升级后的模板才是真正兼容,而不是暂时绕过限制。