Skip to content

@mailpeek/components

Vue components that compile to cross-client email HTML. Build emails with Vue's component model and render them to email-safe HTML strings on the server.

Installation

bash
npm install @mailpeek/components

Live Preview

This email is built entirely with @mailpeek/components and rendered via the render() function. Switch between Gmail, Outlook, and Raw to see how it looks across clients.

Rendering email...

Component Reference

Document Structure

EmailHtml

The root <html> wrapper with XHTML namespaces for Outlook VML support.

PropTypeDefaultDescription
langstring'en'Language attribute
dir'ltr' | 'rtl''ltr'Text direction
vue
<EmailHtml lang="en" dir="ltr">
  <EmailHead />
  <EmailBody>...</EmailBody>
</EmailHtml>

EmailHead

Renders <head> with essential email meta tags (charset, viewport, format-detection, Apple reformat prevention). Add custom <style> or <meta> tags via the default slot.

PropTypeDefaultDescription
titlestringDocument title
vue
<EmailHead title="Order Confirmation">
  <style>
    @media (prefers-color-scheme: dark) {
      .dark-bg { background-color: #1a1a1a !important; }
    }
  </style>
</EmailHead>

EmailBody

The <body> wrapper with email-safe resets (margin, padding, text-size-adjust).

PropTypeDefaultDescription
backgroundColorstring'#ffffff'Background color
styleCSSPropertiesStyle overrides
vue
<EmailBody backgroundColor="#f4f4f5">
  ...
</EmailBody>

Layout

EmailContainer

Centered, max-width table container. The outermost content wrapper for most emails.

PropTypeDefaultDescription
maxWidthnumber600Maximum width in pixels
align'left' | 'center' | 'right''center'Horizontal alignment
backgroundColorstringBackground color
styleCSSPropertiesStyle overrides
vue
<EmailContainer :maxWidth="600">
  ...
</EmailContainer>

EmailSection

A full-width table section. Use for grouping content with shared background/padding.

PropTypeDefaultDescription
backgroundColorstringBackground color
paddingstringCSS padding (e.g. '16px 24px')
styleCSSPropertiesStyle overrides
vue
<EmailSection padding="32px 24px" backgroundColor="#ffffff">
  ...
</EmailSection>

EmailRow

A table row for multi-column layouts. Place EmailColumn components inside.

PropTypeDefaultDescription
styleCSSPropertiesStyle overrides
vue
<EmailRow>
  <EmailColumn width="50%">Left</EmailColumn>
  <EmailColumn width="50%">Right</EmailColumn>
</EmailRow>

EmailColumn

A table cell for use inside EmailRow.

PropTypeDefaultDescription
widthstringColumn width (e.g. '50%', '200px')
align'left' | 'center' | 'right'Horizontal alignment
valign'top' | 'middle' | 'bottom''top'Vertical alignment
backgroundColorstringBackground color
paddingstringCSS padding
styleCSSPropertiesStyle overrides

Content

EmailText

A paragraph with email-safe defaults.

PropTypeDefaultDescription
fontSizenumber16Font size in pixels
lineHeightnumber1.5Line height multiplier
fontFamilystring'Arial, sans-serif'Font family
colorstring'#333333'Text color
align'left' | 'center' | 'right''left'Text alignment
styleCSSPropertiesStyle overrides
vue
<EmailText :fontSize="14" color="#6b7280" align="center">
  Thanks for signing up!
</EmailText>

EmailHeading

A heading element (h1–h6) with email-safe defaults.

PropTypeDefaultDescription
as'h1' | 'h2' | ... | 'h6''h2'Heading level
fontSizenumber24Font size in pixels
lineHeightnumber1.3Line height multiplier
fontFamilystring'Arial, sans-serif'Font family
colorstring'#333333'Text color
align'left' | 'center' | 'right''left'Text alignment
styleCSSPropertiesStyle overrides
vue
<EmailHeading as="h1" :fontSize="28" align="center">
  Welcome!
</EmailHeading>

EmailButton

A bulletproof button using an <a> tag with inline styles.

PropTypeDefaultDescription
hrefstringrequiredLink URL
backgroundColorstring'#007bff'Button background
colorstring'#ffffff'Text color
borderRadiusnumber4Border radius in pixels
fontSizenumber16Font size in pixels
paddingXnumber24Horizontal padding
paddingYnumber12Vertical padding
align'left' | 'center' | 'right''center'Alignment
styleCSSPropertiesStyle overrides
vue
<EmailButton href="https://example.com" backgroundColor="#00b2ad" :borderRadius="8">
  Get Started
</EmailButton>

EmailImage

An image with email-safe resets (display block, border 0, no outline).

PropTypeDefaultDescription
srcstringrequiredImage URL
altstring''Alt text
widthnumberWidth in pixels
heightnumberHeight in pixels
align'left' | 'center' | 'right'Alignment
styleCSSPropertiesStyle overrides
vue
<EmailImage src="https://example.com/logo.png" alt="Logo" :width="150" align="center" />

An inline link with target="_blank".

PropTypeDefaultDescription
hrefstringrequiredLink URL
colorstring'#007bff'Link color
fontSizenumberFont size in pixels
fontFamilystring'Arial, sans-serif'Font family
styleCSSPropertiesStyle overrides
vue
<EmailText>
  Questions? <EmailLink href="mailto:hi@acme.com" color="#00b2ad">Email us</EmailLink>
</EmailText>

EmailDivider

A horizontal divider.

PropTypeDefaultDescription
colorstring'#e0e0e0'Line color
heightnumber1Height in pixels
marginstring'16px 0'CSS margin
styleCSSPropertiesStyle overrides
vue
<EmailDivider color="#e4e4e7" />

EmailPreviewText

Hidden text shown in the inbox preview. Pads with invisible characters to prevent email clients from pulling body content.

PropTypeDefaultDescription
textstringrequiredPreview text
vue
<EmailPreviewText text="Your order has been confirmed." />

Full Example

The live preview above is built from this template, which uses all 14 components:

vue
<script setup>
import {
  EmailHtml, EmailHead, EmailBody, EmailContainer,
  EmailSection, EmailRow, EmailColumn, EmailText,
  EmailHeading, EmailButton, EmailImage, EmailLink,
  EmailDivider, EmailPreviewText,
} from '@mailpeek/components'
</script>

<template>
  <EmailHtml>
    <EmailHead title="Welcome to Launchpad" />
    <EmailBody backgroundColor="#f0f4f8">
      <EmailPreviewText text="Your account is ready. Here's everything you need to get started." />

      <EmailSection padding="48px 20px">
        <EmailContainer :maxWidth="600">

          <!-- Teal header banner -->
          <EmailSection
            padding="36px 48px 32px"
            backgroundColor="#0d9488"
            :style="{ borderRadius: '12px 12px 0 0', textAlign: 'center' }"
          >
            <EmailImage
              src="https://example.com/icon.png"
              alt=""
              :width="48"
              :height="48"
              align="center"
              :style="{ borderRadius: '10px', backgroundColor: 'rgba(255,255,255,0.2)', marginBottom: '16px' }"
            />
            <EmailHeading as="h1" :fontSize="28" align="center" color="#ffffff">
              Launchpad
            </EmailHeading>
          </EmailSection>

          <!-- Hero -->
          <EmailSection padding="48px 48px 32px" backgroundColor="#ffffff">
            <EmailHeading as="h2" :fontSize="24" color="#0f172a">
              Welcome aboard, Sarah! 👋
            </EmailHeading>
            <EmailText :fontSize="16" :lineHeight="1.7" color="#475569">
              Your Launchpad account is ready. You're joining thousands of
              developers who ship faster with better tooling.
            </EmailText>
            <EmailButton
              href="https://example.com/get-started"
              backgroundColor="#0d9488"
              :borderRadius="6"
              :paddingX="32"
              :paddingY="14"
              align="left"
            >
              Get started →
            </EmailButton>
          </EmailSection>

          <EmailSection padding="0 48px" backgroundColor="#ffffff">
            <EmailDivider color="#e2e8f0" :style="{ margin: '0' }" />
          </EmailSection>

          <!-- Features with icon + text rows -->
          <EmailSection padding="32px 48px 24px" backgroundColor="#ffffff">
            <EmailHeading as="h3" :fontSize="18" color="#0f172a">
              Three things to do first
            </EmailHeading>

            <EmailRow :style="{ marginBottom: '24px' }">
              <EmailColumn width="48px" valign="top">
                <EmailImage
                  src="https://example.com/icon-cli.png"
                  alt="" :width="40" :height="40"
                  :style="{ borderRadius: '50%' }"
                />
              </EmailColumn>
              <EmailColumn valign="top" padding="0 0 0 16px">
                <EmailText :fontSize="15" color="#0f172a" :style="{ fontWeight: '600', margin: '0 0 4px 0' }">
                  Install the CLI
                </EmailText>
                <EmailText :fontSize="14" color="#64748b" :style="{ margin: '0' }">
                  Run npm install -g launchpad-cli to connect your local environment.
                </EmailText>
              </EmailColumn>
            </EmailRow>

            <!-- ...repeat for more features... -->
          </EmailSection>

          <!-- Testimonial -->
          <EmailSection padding="32px 48px" backgroundColor="#f8fafc">
            <EmailText :fontSize="15" color="#334155" :style="{ fontStyle: 'italic' }">
              "Launchpad cut our deployment time from 20 minutes to under 2."
            </EmailText>
            <EmailText :fontSize="13" color="#64748b">
              — Marcus Chen, Lead Engineer
            </EmailText>
          </EmailSection>

          <!-- Footer -->
          <EmailSection
            padding="32px 48px"
            backgroundColor="#f8fafc"
            :style="{ borderRadius: '0 0 12px 12px' }"
          >
            <EmailText :fontSize="13" color="#94a3b8" align="center">
              <EmailLink href="#" color="#64748b">Unsubscribe</EmailLink> ·
              <EmailLink href="#" color="#64748b">Privacy Policy</EmailLink> ·
              <EmailLink href="#" color="#64748b">View in browser</EmailLink>
            </EmailText>
          </EmailSection>

        </EmailContainer>
      </EmailSection>
    </EmailBody>
  </EmailHtml>
</template>

render() Function

Convert any Vue email component to an HTML string on the server:

ts
import { render } from '@mailpeek/components'
import MyEmail from './MyEmail.vue'

// Basic render
const html = await render(MyEmail)

// With props
const html = await render(MyEmail, { name: 'Alice' })

// With client-specific CSS filtering
const html = await render(MyEmail, { name: 'Alice' }, { client: 'gmail' })

// Without DOCTYPE
const html = await render(MyEmail, {}, { document: false })
OptionTypeDefaultDescription
documentbooleantruePrepend email DOCTYPE
client'gmail' | 'outlook'Apply client CSS filtering

Released under the MIT License.