GmailのURLをMessage-ID(RFC822形式)で取得するブラウザの拡張機能

# GmailのURLをMessage-ID(RFC822形式)で取得するブラウザの拡張機能
## 0. はじめに
Gmail ユーザーのみなさん。こんにちは。GmailのMessage-IDに基づくURLを欲しくないですか？私はほしいです。だから作りました。ツールを作った経緯は次のとおりです。
1. Gmailは探しにくい
Gmail は世界中にはびこっています。しかし、Gmailの検索には難儀しています。「三上さん」から届いたメールを検索しようとして、「三上」と入力すると、数字の３が入ったメールがことごとく引っかかります。「"三上"」とすればまだ良いのですが、そういう問題なのかな？と思います。だから、大切なメールは、URLとして残しておきたいです。
　
2. 他の人とも情報共有できるURLになりうる
RFC822形式の Message-ID は、送信されるとユニークなIDとして記録されます。だから、これに基づいてGmailへのURLを作成することができれば、送信者も受信者も同じURLで参照できます。（「ほら、以前送ったあれ！」を特定できます。）だけじゃなく、メーリングリストの場合には、メンバー全員が同じURLで参照できます。
　
3. 今まであったツールは使えなくなってしまった
[同志（←単に同じように考えた人たち）が作ってくれたツール](https://github.com/code-orange/Gmail-message-ID-finder)は、マニフェスト2 なので、今は使えなくなってしまいました。inboxSDK もうまく機能しません。

そこで、新たに作りましょう。
## 1. 設計
* inboxSDK を使わない。
* Gmail の「<> メッセージのソースを表示」ボタンを押して、開いた途端に"クリップボード" にGmail のURLが保存されるようにする。（その旨メッセージも表示される。）
* 拡張機能の公開の仕方はよくわからないので、ストアなどに置かない。フォルダに置いて読み込む方法は、[【猿でもできる】Chrome拡張機能の作り方](https://qiita.com/mizo__/items/5951a7d94ab0ff8cf49b)などをありがたく参照します。


## 2. ソース
```json:manifest.json
{
	"manifest_version": 3,
	"name": "URL for Gmail by MsgID822",
	"version": "1.0",
	"permissions": ["activeTab", "scripting"],
	"host_permissions": ["https://mail.google.com/*"],
	"action": {
		"default_icon": {
		"16": "icon16.png",
		"48": "icon48.png",
		"128": "icon128.png"
	  }
	},
	"content_scripts": [
	  {
		"matches": ["https://mail.google.com/mail/*?ik=*"],
		"js": ["content.js"],
		"run_at": "document_start"
	  }
	]
  }
```
```javascript:content.js
document.addEventListener('DOMContentLoaded', function() {
    setTimeout(function() {
        try {
            const preElement = document.querySelector('pre');
            if (!preElement) throw new Error('PRE element not found');
            const fullText = preElement.textContent;
            const messageIdMatch = fullText.match(/^Message-ID: <(.+?)>/im);
            if (messageIdMatch) {
                const messageId = messageIdMatch[1];
                console.log('Extracted Message ID:', messageId);

                // メッセージIDをURLエンコード
                const encodedMessageId = encodeURIComponent(messageId);
                console.log('Encoded Message ID:', encodedMessageId);

                // Gmailの検索URLを生成
                const searchUrl = `https://mail.google.com/mail/#search/rfc822msgid:${encodedMessageId}`;
                console.log('Generated search URL:', searchUrl);

                // URLをクリップボードにコピー
                navigator.clipboard.writeText(searchUrl).then(function() {
                    // 成功した場合
                    alert('Search URL has been copied to clipboard!');
                }, function(err) {
                    // エラーが発生した場合
                    console.error('Could not copy text: ', err);
                });
            } else {
                throw new Error('Message ID not found.');
            }
        } catch (error) {
            console.error('Error in script:', error);
        }
    }, 300); // GmailのDOMが読み込まれるまでに少し遅延を設ける
});
```
※ アイコンは適当に作ってください！（私は[同志が作ってくれたツール](https://github.com/code-orange/Gmail-message-ID-finder)のものを拝借しています。）

## 3. 操作方法
### 3-1. 拡張機能の導入
* 上記の manifest.json, contents.js, アイコンを特定のフォルダに格納する。
* ブラウザ（以下、Edgeの場合）で「…」＞「拡張機能」＞「拡張機能の管理」へ進む。
* 「開発者モード」を有効にする
* 「展開して読み込み」で、manifest.json などを格納したフォルダを指定する。
### 3-2. 使い方
* Gmail に拡張機能が入ったブラウザでアクセスする。メールを開く。
* 縦に3点並んだところをクリックして「<> メッセージのソースを表示」をクリックする。
* クリップボードに、そのメールへのURLが格納されるので、適宜使う。

## 4. コメント
* GmailがMessage-ID で検索できることは、例えば[Gmail 内のメールをメッセージ ID から探す方法について教えてください](https://support.gluegent.com/hc/ja/articles/206259262-Gmail-%E5%86%85%E3%81%AE%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%92%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8-ID-%E3%81%8B%E3%82%89%E6%8E%A2%E3%81%99%E6%96%B9%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E6%95%99%E3%81%88%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84)を参照してください。
* 「<> メッセージのソースを表示」をクリックすると最上部に、RFC822のMessage-ID が表示されるようですね。つまり、このような仕組みはいらないということだったのか。以前は出ていなかったように思うので不便に思っていたのですが…
* Windows + MS Edge で試していました。Linux + Google Chrome でも動きました！
* Message-IDには、"+" など、そのままではURLとして使えない文字も含まれています。そこで、encodeURIComponent()を使っています。