Skip to main content

Overview

The getEmail method converts Yoopta editor content into email-compatible HTML with proper structure, inline styles, and table-based layout. It’s designed specifically for email clients which have limited CSS support.

Usage

import { useYooptaEditor } from '@yoopta/editor';

function SendEmailButton() {
  const editor = useYooptaEditor();

  const handleSend = async () => {
    const emailHtml = editor.getEmail(editor.children);
    
    await sendEmail({
      to: '[email protected]',
      subject: 'Your document',
      html: emailHtml,
    });
  };

  return <button onClick={handleSend}>Send Email</button>;
}

Signature

function getEmail(
  editor: YooEditor,
  content: YooptaContentValue,
  options?: EmailTemplateOptions
): string

Parameters

editor
YooEditor
required
The editor instance (automatically provided when called as editor.getEmail())
content
YooptaContentValue
required
The content to convert to email HTML. Typically editor.children for current content.
options
EmailTemplateOptions
Optional configuration for the email template structure and styling

Returns

string - Complete email-compatible HTML document

Email Template Options

type EmailTemplateOptions = {
  head?: {
    styles?: StyleElement[];     // Custom CSS styles
    meta?: MetaElement[];        // Meta tags
    title?: string;              // Email title
  };
  body?: {
    attrs?: ElementAttributes;   // Body element attributes
  };
  container?: {
    attrs?: ElementAttributes;   // Container table attributes
  };
  customTemplate?: (content: string) => string;  // Custom wrapper
};

Default Options

const DEFAULT_OPTIONS: EmailTemplateOptions = {
  head: {
    meta: [
      { content: 'width=device-width', name: 'viewport' },
      { charset: 'UTF-8' },
      { content: 'IE=edge', 'http-equiv': 'X-UA-Compatible' },
    ],
  },
  body: {
    attrs: {
      style: {
        margin: '0 auto',
        padding: 0,
        width: '900px',
      },
    },
  },
  container: {
    attrs: {
      style: {
        margin: '0 auto',
        width: '600px',
      },
    },
  },
};

Output Structure

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en">
<head>
  <title>Email-Builder</title>
  <meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
  <meta content="width=device-width" name="viewport">
  <!-- Additional meta tags and styles -->
</head>
<body id="yoopta-email" style="margin: 0 auto; padding: 0; width: 900px;">
  <table style="margin: 0 auto; width: 600px;">
    <tbody>
      <tr>
        <td>
          <!-- Email content here -->
        </td>
      </tr>
    </tbody>
  </table>
</body>
</html>

Examples

Basic Email Export

function ExportEmailButton() {
  const editor = useYooptaEditor();

  const handleExport = () => {
    const emailHtml = editor.getEmail(editor.children);
    console.log(emailHtml);
  };

  return <button onClick={handleExport}>Export Email HTML</button>;
}

Custom Styling

function CustomStyledEmail() {
  const editor = useYooptaEditor();

  const handleExport = () => {
    const emailHtml = editor.getEmail(editor.children, {
      head: {
        title: 'Newsletter',
        styles: [
          {
            id: 'custom-styles',
            content: `
              body { font-family: 'Helvetica', Arial, sans-serif; }
              h1 { color: #2c3e50; }
              p { line-height: 1.6; color: #34495e; }
            `,
          },
        ],
      },
      body: {
        attrs: {
          style: {
            backgroundColor: '#f4f4f4',
            margin: '0 auto',
            padding: '20px',
            width: '100%',
          },
        },
      },
      container: {
        attrs: {
          style: {
            backgroundColor: '#ffffff',
            borderRadius: '8px',
            margin: '0 auto',
            padding: '30px',
            width: '600px',
          },
        },
      },
    });

    console.log(emailHtml);
  };

  return <button onClick={handleExport}>Export Styled Email</button>;
}

Custom Template Wrapper

function BrandedEmail() {
  const editor = useYooptaEditor();

  const handleExport = () => {
    const emailHtml = editor.getEmail(editor.children, {
      customTemplate: (content) => `
        <!DOCTYPE html>
        <html>
          <head>
            <title>Branded Email</title>
          </head>
          <body>
            <div style="background: #f0f0f0; padding: 20px;">
              <div style="background: white; max-width: 600px; margin: 0 auto;">
                <div style="background: #007bff; color: white; padding: 20px;">
                  <h1>Company Name</h1>
                </div>
                <div style="padding: 20px;">
                  ${content}
                </div>
                <div style="background: #f8f9fa; padding: 20px; text-align: center;">
                  <p>© 2024 Company Name. All rights reserved.</p>
                </div>
              </div>
            </div>
          </body>
        </html>
      `,
    });

    console.log(emailHtml);
  };

  return <button onClick={handleExport}>Export Branded Email</button>;
}

Send via Email API

function SendEmailButton() {
  const editor = useYooptaEditor();
  const [sending, setSending] = useState(false);

  const handleSend = async () => {
    setSending(true);
    try {
      const emailHtml = editor.getEmail(editor.children, {
        head: { title: 'Newsletter - January 2024' },
      });

      await fetch('/api/send-email', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          to: '[email protected]',
          subject: 'January Newsletter',
          html: emailHtml,
        }),
      });

      alert('Email sent successfully!');
    } catch (error) {
      alert('Failed to send email');
    } finally {
      setSending(false);
    }
  };

  return (
    <button onClick={handleSend} disabled={sending}>
      {sending ? 'Sending...' : 'Send Email'}
    </button>
  );
}

Newsletter Template

function NewsletterExport() {
  const editor = useYooptaEditor();

  const exportNewsletter = () => {
    return editor.getEmail(editor.children, {
      head: {
        title: 'Monthly Newsletter',
        meta: [
          { content: 'width=device-width, initial-scale=1.0', name: 'viewport' },
          { charset: 'UTF-8' },
        ],
        styles: [
          {
            content: `
              @media only screen and (max-width: 600px) {
                .container { width: 100% !important; }
                .content { padding: 10px !important; }
              }
            `,
          },
        ],
      },
      body: {
        attrs: {
          style: {
            margin: 0,
            padding: 0,
            backgroundColor: '#f6f6f6',
            fontFamily: 'Arial, sans-serif',
          },
        },
      },
      container: {
        attrs: {
          className: 'container',
          style: {
            width: '600px',
            margin: '0 auto',
            backgroundColor: '#ffffff',
          },
        },
      },
    });
  };

  const handleExport = () => {
    const html = exportNewsletter();
    // Download or send
    const blob = new Blob([html], { type: 'text/html' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'newsletter.html';
    a.click();
  };

  return <button onClick={handleExport}>Export Newsletter</button>;
}

Preview Email

function EmailPreview() {
  const editor = useYooptaEditor();
  const [previewHtml, setPreviewHtml] = useState('');

  useEffect(() => {
    const handleChange = () => {
      const html = editor.getEmail(editor.children);
      setPreviewHtml(html);
    };

    handleChange();
    editor.on('change', handleChange);
    return () => editor.off('change', handleChange);
  }, [editor]);

  return (
    <div className="email-preview">
      <h3>Email Preview</h3>
      <iframe
        srcDoc={previewHtml}
        style={{ width: '100%', height: '600px', border: '1px solid #ccc' }}
        title="Email Preview"
      />
    </div>
  );
}

Email-Specific Features

Table-Based Layout

Email HTML uses tables for layout compatibility:
<table style="margin: 0 auto; width: 600px;">
  <tbody>
    <tr>
      <td>
        <!-- Content -->
      </td>
    </tr>
  </tbody>
</table>

Inline Styles

All styles are inlined for maximum email client compatibility:
<p style="margin: 0; padding: 10px; color: #333;">
  Content here
</p>

XHTML Doctype

Uses XHTML 1.0 Transitional for better email client support:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Plugin Email Serializers

Plugins define email-specific serializers:
const ParagraphPlugin = {
  parsers: {
    email: {
      serialize: (element, text, meta) => {
        return `<p style="margin: 0 0 16px 0; line-height: 1.6;">${text}</p>`;
      },
    },
  },
};

Use Cases

  • Email Newsletters: Generate HTML for email campaigns
  • Notifications: Send formatted notifications via email
  • Reports: Email formatted reports to users
  • Transactional Emails: Create order confirmations, receipts
  • Marketing Emails: Build promotional email content
  • Automated Emails: Generate emails from templates
  • Email Previews: Preview how content looks in email

Email Client Compatibility

The generated HTML is optimized for:
  • Gmail
  • Outlook (desktop and web)
  • Apple Mail
  • Yahoo Mail
  • Mobile email clients
Best practices applied:
  • Table-based layouts
  • Inline CSS styles
  • Limited CSS properties
  • No external stylesheets
  • No JavaScript
  • Minimal web fonts

See Also

Build docs developers (and LLMs) love