                data = attachments_service.read_attachment_bytes(att)
                if data is not None:
                    attachments.append({"filename": att.filename, "content": data,
                                        "mime_type": att.mime_type})
                    att_names.append(att.filename)

        html_problems = message_builder.validate_html(result_html)
        if html_problems:
            log.warning("HTML validation warnings for %s: %s", cr.email, html_problems)

        mime = message_builder.build_mime_message(
            from_email=account.email,   # real authenticated account; never spoofed
            to_email=cr.email,
            subject=subject,
            html_body=result_html if campaign.message_type != "plain" else "",
            text_body=result_text,
===TEMPLATES===
    res = engine.substitute(t.body_html, sample.get("recipient", {
        "FirstName": "John", "LastName": "Smith", "CompanyName": "Example Corp",
        "CustomerEmail": "customer@example.com", "Email": "john@example.com"}),
        g, custom_fields=sample.get("custom_fields", {}),
        extra={"unsubscribe_link": "https://example.com/unsubscribe?token=sample"})
    problems = message_builder.validate_html(res.text)
    return {"rendered_html": message_builder.sanitize_preview(res.text),
            "unknown_variables": res.unknown, "missing_variables": res.missing,
            "warnings": problems,
            "generated": {"invoice_number": g.invoice_number, "amount": g.amount,
                          "shipping": g.shipping}}


@router.post("/{template_id}/test-pdf")
async def test_pdf(template_id: int, sample: dict = {},
===TESTSEND===
        if not template or template.user_id != user.id:
            raise HTTPException(status_code=404, detail="Template not found")
    body_html = template.body_html if template else payload.body_html
    body_text = template.body_text if template else payload.body_text
    if not body_html and not body_text:
        raise HTTPException(status_code=400, detail="Provide a template or message body")

    problems = message_builder.validate_html(body_html) if body_html else {}
    if problems.get("errors"):
        raise HTTPException(status_code=400,
                            detail=f"HTML rejected: {'; '.join(problems['errors'])}")

    # fake recipient record for variable substitution (test only)
    class _FakeRecipient:
        pass
    fr = _FakeRecipient()
    fr.email = str(payload.to_email)
    fr.first_name = "Test"
    fr.last_name = "Recipient"
    fr.company_name = await get_setting(db, "company_name", "Acme Corp") or "Acme Corp"
    fr.company_phone = "555-0100"
