くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Markdownで書いたメール本文をSendGridで送信する

SendGridを使ってメールを送ってるけど、
Dynamic Templateで、長文を送るのがめんどくさい。。

本文はMarkdownでかければなーと思い、
いろいろ調べたときの備忘録。

まとめ

流れとしてはこんな感じ。

  • Dynamic Templateでベース部分を作成
  • Markdownで書いた本文をmicromarkでHTMLに変換
  • 変換したHTMLをdynamicTemplateDataに設定して送信

ベース部分の作成

Dynamic Templateで共通部分を作っておく。

本文が差し込まれるところには、以下の感じのコードブロックを追加し、
HTMLが有効になる形式で追加にしておく。

<div>
{{{message}}}
</div>

Handlebarsの使用 | Twilio

スタイルなどは、「ADVANCED>Edit HTML Head」で設定。

<head>
  <style>
  p {
    margin-top: 1rem;
    margin-bottom: 1rem;
    font-size: 0.9rem;
  }

  h2,h3 {
    margin-top: 2rem;
    margin-bottom: 1rem;
  }
  </style>
</head>

MarkdownをHTMLに変換

まずはインストール。

$ npm i micromark

micromarkの使い方はシンプルで、
markdownの文字列を渡すとHTMLが返ってくる。

import { micromark } from "micromark";
import fs from "fs";

async function main() {
  // .mdをHTMLに変換
  const markdownFilePath = "...";
  const fileContent = fs.readFileSync(markdownFilePath, { encoding: "utf-8" });
  const htmlContent = micromark(fileContent);
}

main().then();

ただ、micromarkは、ES Moduleのみのため、
CommonJSのプロジェクトの場合、ES Modlue対応が必要。

TypeScriptのESMでハマる - くらげになりたい。

Markdown内でFront Matterを使いたいときは、
js-yamlflatを使って区切り文字で分割する。

import { micromark } from "micromark";
import fs from "fs";

// npm i flat js-yaml
import flat from "flat";
import yaml from "js-yaml";

const FRONTMATTER_DELIMITER = "---";
export function parseFrontMatter(content: string) {
  let data: Record<string, any> = {};
  if (content.startsWith(FRONTMATTER_DELIMITER)) {
    const idx = content.indexOf("\n" + FRONTMATTER_DELIMITER);
    if (idx !== -1) {
      const frontmatter = content.slice(4, idx);
      if (frontmatter) {
        data = yaml.load(frontmatter) as Record<string, any>;
        content = content.slice(idx + 4);
      }
    }
  }

  data = flat.unflatten(data || {}, {}) as Record<string, any>;
  return { content, data: data };
}

async function main() {
  // .mdをHTMLに変換
  const markdownFilePath = "...";
  const fileContent = fs.readFileSync(markdownFilePath, { encoding: "utf-8" });
  
  // front-matterと本文の取得
  const { content, data } = parseFrontMatter(fileContent);
  const htmlContent = micromark(content);
}

main().then();

こんな感じでメールの件名を指定できるようにしている。

---
title: 【SSSAPI】5月の更新情報まとめ
---

## 5月の更新情報まとめ
...

変換したHTMLをSendGridで送信

あとは、SendGridのクライアントライブラリから送信すればOK

$ npm i @sendgrid/mail
import { micromark } from "micromark";
import fs from "fs";

// npm i @sendgrid/mail
import sgMail from "@sendgrid/mail";

sgMail.setApiKey(SENDGRID_API_KEY);

async function main() {
  // .mdをHTMLに変換
  const markdownFilePath = "...";
  const fileContent = fs.readFileSync(markdownFilePath, { encoding: "utf-8" });
  const htmlContent = micromark(fileContent);
  
  // メールの送信
  const data: sgMail.MailDataRequired = {
    to: "user@example.com",
    from: "info@my-service.com",
    templateId: "<dynamic-template-id", 
    dynamicTemplateData: {
      title: "Mail Title",
      message: htmlContent
    }
  };
  await sgMail.send(data);
}

main().then();

以上!! 便利(´ω`)

参考にしたサイトさま