Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Inky Laravel Package

christhompsontldr/laravel-inky

Laravel Inky integrates Zurb's Inky email templating with Laravel, letting you write clean, component-based Blade views that compile into responsive HTML emails. It simplifies building mobile-friendly transactional messages with reusable partials and Laravel Mail.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and confirm what you actually got. The package is a thin service-provider wrapper, so before writing a single template, read three things in vendor/christhompsontldr/laravel-inky:

  1. composer.json → extra.laravel.providers (auto-discovery on Laravel 5.5+), the declared laravel/framework and php constraints, and which Inky implementation it wraps (require block — likely a PHP port such as lorenzhs/inky). The wrapper's behavior is the underlying library's behavior; you need to know which one you're trusting.
  2. The service provider → the only thing that matters operationally is how it hooks the view layer: does it register a custom view engine for a file extension (e.g. .inky.php), wrap Blade::compileString, or patch Mailable rendering? That single fact determines your template filenames, your debugging workflow, and your upgrade risk.
  3. Any published config → compiled-output caching, view extension, output options. If there is none, assume it recompiles on every render until you prove otherwise.
composer require christhompsontldr/laravel-inky
# Only if a config file is shipped — take the provider FQCN from extra.laravel.providers, don't guess:
php artisan vendor:publish --provider="<Vendor>\Inky\InkyServiceProvider"

Pin the exact version. Zero stars, zero dependents, one maintainer. composer require christhompsontldr/laravel-inky:1.x.y (exact), not ^1.0. Treat it as vendored code you now own.

First use case: one transactional email, end to end. Do not start with a marketing template. Build a receipt or password-reset: one <container>, one <row>, 1–2 <columns>, a <button>. Point an existing Mailable at it via ->view('emails.receipt') and send to a Mailtrap/log transport. You are validating the compiler wiring, not the design.

{{-- resources/views/emails/receipt.inky.php (extension per your provider check) --}}
<container>
  <row>
    <columns small="12" large="8">
      <h1>Thanks, {{ $user->name }}</h1>
      <p>Order #{{ $order->number }} is confirmed.</p>
      <button href="{{ $order->url }}">View order</button>
    </columns>
  </row>
</container>

Render it without sending to inspect output before you involve a transport:

echo (new App\Mail\Receipt($order))->render();

If that prints table HTML, the compiler is wired. If it prints your <columns> tags verbatim, the view engine isn't matching your file extension — that is the most common first-day failure and it is a filename problem, not a package bug.

What you have not installed. Inky is a structural compiler only. You still need (a) Foundation for Emails SCSS compiled to CSS, (b) a CSS inliner in the render path, (c) a cross-client preview harness (Litmus, Email on Acid, or at minimum manual Gmail/Outlook/Apple Mail checks). Budget all three; the package is one of three line items.

Implementation Patterns

Keep Mailables thin, put Inky in the view. The package touches the view layer, not Mail, queues, events, or transport. Your build() stays boring — ->view(), ->subject(), ->with() — and everything Inky-flavored lives in resources/views/emails. This is what makes the rollback a one-line view swap: delete the Inky tag soup, replace with a plain Blade view, done.

Compose layouts, don't repeat containers. Inky components are ordinary Blade-compatible tags, so the normal Blade hierarchy applies:

resources/views/emails/layouts/base.inky.php   <- doctype, <container>, <wrapper>, footer
resources/views/emails/partials/button.inky.php
resources/views/emails/receipt.inky.php         <- @extends + @section

Reusable partials are your defense against the single biggest cost in email work: 20 templates that each drifted independently. One partials/button compiled to Inky's canonical <button> output beats 20 hand-tuned anchor tags.

Render-and-inspect is the inner loop, not "send and check." Wire a local-only preview route so you can iterate without touching a transport:

// routes/web.php, local env only
Route::get('/_mail/{name}', fn ($name) => (new ("App\\Mail\\".Str::studly($name))(/* fixtures */))->render());

Because Inky emits tables, view it in the browser at several widths (375px, 600px, 1024px) to sanity-check the responsive row/column breakpoints before you ever open a real client.

Handle CSS inlining as a separate, explicit step. The package does not inline. Pick your approach and know where it sits in the pipeline:

  • Preferred for day-to-day sanity: inline at render time (a tijsverkoyen/css-to-inline-styles call around the compiled HTML) so preview and production produce identical output.
  • Alternative: a build step that compiles Foundation SCSS and inlines into the Inky output before deploy — fewer moving parts at send time, but the preview route then lies unless it reads the built artifact.

Whatever you choose, make the preview path and the send path share it. If previews look styled and real sends don't, you've found the divergence and you'll waste a day on it.

Snapshot-test every template. Structural compilers are deterministic, which makes regression testing cheap and high-value given how fragile the wrapper is across Laravel majors. One test per template: render the Mailable, assert the compiled HTML matches (or at least contains the expected <table> structure and no un-compiled <columns> tags). That single assertion catches both Inky-spec drift and a silent provider break on the next Laravel upgrade.

public function test_receipt_compiles_to_tables(): void
{
    $html = (new Receipt(Order::factory()->make()))->render();
    $this->assertStringNotContainsString('<columns', $html); // compiler ran
    $this->assertStringContainsString('<table', $html);
    $this->assertMatchesSnapshot($html);
}

Coexist with Markdown mailables by default. Nothing here prevents Mail::markdown() living alongside Inky templates in the same app. Migrate a template to Inky only when its layout is genuinely constrained (multi-column, nested rows, buttons that need Outlook-safe table fallbacks). Markdown mail is upstream-maintained and accessible by default; converting a simple one-paragraph notification to Inky is a pure maintenance downgrade.

Migrate in this order: hand-rolled table HTML first (biggest defect-reduction per unit effort — it deletes <table role="presentation"> boilerplate outright), then an existing Node/Foundation-for-Emails build step (deletes npm/Gulp from CI, but trades the canonical Node Inky for the PHP port — verify parity), Markdown mailables last or never.

Gotchas and Tips

The output will be unstyled and that is not a bug. The single most common first impression: "it's working but everything is Times New Roman, full width." Inky converted your structure correctly; you haven't supplied Foundation CSS or inlined it. Check for this before filing anything.

Verify Laravel/PHP compatibility yourself, don't infer it. Packages that hook the view engine are exactly the class that breaks on Laravel majors (view internals, discovery metadata, PHP floors). Run the spike on your actual target Laravel + PHP version on day one. If the repo can't answer "which Laravel/PHP versions, with CI evidence" in under an hour, that absence is the signal — go straight to the fork-or-wrap-in-house path.

Expect Inky spec drift from the Node canonical implementation. The PHP port trails Zurb's. Divergences cluster in nested <columns>, small/large breakpoints, and <menu>/<callout> output. Diff against canonical Node Inky output on three representative templates (receipt, multi-column marketing, nested/edge case) as a fidelity gate — subtly wrong HTML here only surfaces in client testing, the most expensive place to find it.

Debugging: print the compiled string, never the source. When something looks wrong, (new Mailable(...))->render() gives you the post-compile HTML. Reading the Inky source and guessing which tag misbehaved wastes time. If render() still shows <row>/<columns>, the compiler didn't run — check file extension and provider registration.

Confirm whether compiled output is cached. If it recompiles every render, high-volume notification bursts (order confirmations across thousands of users) pay the compile cost per send. If it does cache, know the invalidation trigger before you spend an afternoon wondering why template edits aren't showing in local preview. This is a repo-answerable question; answer it during the spike, write it down.

Watch the inliner interaction. If you already have view-engine customization or an inliner in the render path, the Inky compile step and the inline step are two passes over the same HTML — ordering matters. Compile → inline → send. Inlining before compiling produces CSS sitting on tags the compiler then rewrites.

Name an owner and a standing tax. Single maintainer, no security disclosure process, no release cadence. Realistic estimate: ~1–2 engineer-days per Laravel major to verify or fork. Make that a conscious staffing decision, not an accident discovered at upgrade time.

The extension points are the provider and the view registration — that's your fork surface. The wrapper is plausibly a few hundred lines. When the package breaks on an upgrade, don't wait for the maintainer: fork, or vendor it and swap the underlying inky PHP library yourself (~200–400 LOC you control). Keep the Mailable interface identical so this is invisible to callers.

Set the abandon trigger before you start. Timeboxed pilot: one engineer, one week, one low-risk template in production, with a written pass/fail on (a) three templates compiling to table HTML, (b) parity with Node Inky on the edge cases, (c) acceptable cross-client render. If any gate fails, the rollback is a one-line view swap on a single Mailable and the cost of finding out was 3–5 engineer-days. Price the real comparison honestly at that gate: this package vs. wrapping the underlying PHP library in-house vs. MJML (larger community, active maintenance) vs. status quo. Given zero dependents, in-house wrapping is arguably the default, not the fallback.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style