Vue-Email

Vue-email is inspired by react-email, it allows us create templates using the vue framework, with components that help us build templates easily and fast.

Installation

To start using vue-email in any vue project, you just need to install the package:

With NPM:


$ npm install vue-email

With Yarn:

$ yarn add vue-email

With PNPM:

$ pnpm install vue-email

Usage

Creating email template

Create a new email template in wherever you want to have your templates, for this case, we can create a template folder, with a template called welcome.vue.

src/templates/welcome.vue

<template>
  <e-html lang="en">
    <e-head />
    <e-preview preview="Welcome to vue-email" />
    <e-section :style="main">
      <e-container :style="container">
        <e-img
          src="https://avatars.githubusercontent.com/u/6128107?s=200&v=4"
          alt="Vue logo"
          :style="logo"
          width="200"
          height="50"
        />
        <e-text :style="paragraph">{{ name }}, welcome to vue-email</e-text>
        <e-text :style="paragraph">A Vue component library for building responsive emails</e-text>
        <e-section :style="btnContainer">
          <e-button :p-x="12" :p-y="12" :style="button" href="https://github.com/Dave136/vue-email">
            View on GitHub
          </e-button>
        </e-section>
        <e-text :style="paragraph">Happy coding!</e-text>
        <e-hr :style="hr" />
        <e-text :style="footer">David Arenas</e-text>
      </e-container>
    </e-section>
  </e-html>
</template>
<script lang="ts" setup>
import { EButton, EContainer, EHead, EHr, EHtml, EImg, EPreview, ESection, EText } from 'vue-email';

defineProps<{ name: string }>();

const fontFamily =  '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif';

const main = {
  backgroundColor: '#ffffff',
};

const container = {
  margin: '0 auto',
  width: '100%',
  padding: '20px 0 48px',
};

const logo = {
  margin: '0 auto',
  height: '6em',
  width: '6em',
};

const paragraph = {
  fontFamily,
  fontSize: '16px',
  lineHeight: '26px',
};

const btnContainer = {
  textAlign: 'center' as const,
};

const button = {
  fontFamily,
  backgroundColor: '#41b883',
  borderRadius: '3px',
  color: '#fff',
  fontSize: '16px',
  textDecoration: 'none',
  textAlign: 'center' as const,
  display: 'block',
};

const hr = {
  borderColor: '#cccccc',
  margin: '20px 0',
};

const footer = {
  fontFamily,
  color: '#8898aa',
  fontSize: '12px',
};
</script>

Rendering the templates

We can use the render function, it receives two params, the first one is the template to render, and the second the params to be used for the template, and then pass the result template in the body of request.

Passing the template in the body, give us the chance of rendering using any server, express, fastify, nuxt in SSR, etc.

src/pages/index.vue

<template>
  <h2>Send email with nodemailer</h2>
  <input type="text" v-model="name" />
  <button @click="handleClick">Sent email</button>
</template>

<script lang="ts" setup>
import { render } from 'vue-email';
import WelcomeTemplate from '~/templates/welcome.vue';

const name = ref('Dave');

const handleClick = async () => {
  const template = await render(WelcomeTemplate, { name });
  const data = await $fetch('/api/email', {
    method: 'post',
    body: {
      template,
    },
  });
};
</script>

Send email

In this example i using nuxt v3 because it allows us to set api inside own project, and define multiple api routes.

Here we just extract the template of the request body, and send the email passing the template in the sendMail function of the nodemailer package.

src/server/api/email.post.ts

import nodemailer from 'nodemailer';

export default defineEventHandler(async (event) => {
  const body = await readBody(event);

  const testAccount = await nodemailer.createTestAccount();

  const transporter = nodemailer.createTransport({
    host: process.env.HOST || 'smtp.ethereal.email',
    port: 587,
    secure: false,
    auth: {
      user: testAccount.user,
      pass: testAccount.pass,
    },
  });

  const options = {
    from: 'you@example.com',
    to: 'user@gmail.com',
    subject: 'hello world',
    html: body.template,
  };

  await transporter.sendMail(options);
});

If you are not using the server in nuxt, you can easily implement on any framework for example using express:

import express from 'express';
import nodemailer from 'nodemailer';

const app = express();

app.use(express.json());

app.post('/api/send-email', async (req, res) => {
  const { template } = req.body;

  const testAccount = await nodemailer.createTestAccount();

  const transporter = nodemailer.createTransport({
    host: process.env.HOST || 'smtp.ethereal.email',
    port: 587,
    secure: false,
    auth: {
      user: testAccount.user,
      pass: testAccount.pass,
    },
  });

  const options = {
    from: 'you@example.com',
    to: 'user@gmail.com',
    subject: 'hello world',
    html: template,
  };

  await transporter.sendMail(options);

  return res.json({ message: "Email sent" });
});

app.listen(3001);

Documentation

Get the full documentation [here]()

Components

You can see the components, listed below:

Integrations

Emails built with vue-email can be converted into HTML or plain text, and sent using any email service provider. You can see examples here: