Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Gmailの下書きをMarkdownで書くためのアプリをelectron-vueで作る

More than 1 year has passed since last update.

勤務先では日報をメール(Gmail)で出すこととなっているのですが、いちいちメール画面を開いて記録つけてると気が散るしいまいち編集画面が使いやすくない(※個人の感想です)ので、自分は下書きは自動バックアップ機能のあるVisual Studio Codeで書いていたり。

それだと書式が付けられないので、Markdownで清書するアプリを書いてみます。

ソースはこちら。
https://github.com/kuinaein/md-gmail/compare/0b4913e...3d66c13

なお、Node.jsでのGmail APIの呼び出し方は下記の記事にも書いたのでそのあたりは割愛します。

ライブラリのインストール

Markdownライブラリはmarkedを使うことにします。

vue init simulatedgreg/electron-vue md-gmail
cd md-gmail
yarn add --dev pug-html-loader
yarn add googleapis urlsafe-base64 moment marked html-escaper
yarn add bootstrap-honoka

Markdownプレビュー画面

Googleアカウントの認証については別の記事で書いたのでざっくり飛ばします。

Markdownの整形自体はmarkedがやってくれるので画面自体はシンプルなものです。
ただmarkedはテーブルタグに枠線を付けてくれないので、表示画面ではひとまずスタイルシートで補っています。vue-loaderは画面にない要素へのスタイル定義を削ろうとするので、「>>>」で子要素へ影響するものと指示しておきます。

<template lang="pug">
.container
  textarea(v-model="md" rows="15" style="width:90vw")
  p プレビュー:
  div(id="formatted" v-html="formatted")
  button.btn.btn-primary(type="button" @click="saveAsDraft") Gmail下書きに保存
</template>

<style scoped>
#formatted >>> table {
  border-collapse: collapse;
}
#formatted >>> th, #formatted >>> td {
  border: solid 1px black;
}
</style>

<script>
import moment from 'moment'
import URLSafeBase64 from 'urlsafe-base64'
import { google } from 'googleapis'
import marked from 'marked'
import { escape as escapeHtml } from 'html-escaper'

const BOUNDARY = 'MY_BOUNDARY_GX9900'

export default {
  data () {
    return {
      md: ''
    }
  },
  computed: {
    formatted () {
      return marked(this.md)
    }
  },
  // 後略
}
</script>

Gmailの下書きへ保存

markedの出力結果を保存するだけ……なのですがいくつか注意点があります。

  • Gmail APIにはRFC822に沿った生のメールデータをURLセーフなBase64形式にして渡す必要がある。
  • HTMLメールの場合はContent-Type: multipart/alternativeとして送る必要がある。全体をtext/htmlにしてもダメ。
    • ただし、テキスト形式の本文を含める必要はない。
  • HTMLメールにしても<head>タグの内容は無視される。style属性等に書き換える必要がある。

また、本文のMarkdown形式でのソースも残しておきたいので、それも文中に含めることとします。

const body = this.formatted.replace(/<table>/g,
  '<table border="1" style="border-collapse:collapse">') + `
<br/><br/>
<small>Markdownソース:
<textarea readonly rows="1" cols="1">${escapeHtml(this.md)}</textarea></small>
`
const subject = '【日報】' + moment().format('YYMMDD')
const email = `Subject: =?UTF-8?B?${URLSafeBase64.encode(Buffer.from(subject))}?=
Content-Type: multipart/alternative; boundary="${BOUNDARY}"

--${BOUNDARY}
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: base64

${Buffer.from(body).toString('base64')}
--${BOUNDARY}--`
gmail.users.drafts.create({
  userId: 'me',
  resource: { message: { raw: URLSafeBase64.encode(Buffer.from(email)) } }
})
kuinaein
非IT系中小企業のシステム担当です。
https://kuinaein.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away