            campaign.failed_count += 1
            db.commit()
            return {"ok": False, "status": "perm_failed", "reason": "no template"}

        var_cfg = dict(campaign.variable_config or {})
        engine = VariableEngine(var_cfg)
        g = GeneratedValues(
            invoice_number=cr.generated_invoice_number,
            amount=cr.generated_amount,
            shipping=cr.generated_shipping,
            random_name=engine.generate_random_name(),
            invoice_date=var_cfg.get("invoice_date", ""),
            due_date=var_cfg.get("due_date", ""),
            phone=cr.generated_phone or var_cfg.get("company_phone", ""),
        )
        unsub_url = _unsubscribe_url(recipient, campaign)
        rec = _recipient_dict(recipient)
        cf = (recipient.custom_fields if recipient else None) or {}
        result_html = engine.substitute(template.body_html, rec, g, custom_fields=cf,
                                        extra={"unsubscribe_link": unsub_url}).text
        result_text = engine.substitute(template.body_text or _plain_fallback(result_html),
