Thunderbird 153(Meadow)からメールに付けるタグの仕様が変更になり、日本語(非 ASCII)で設定したタグが正しく動作しなくなってしまいました。
何十万件のメールに、タグが 100 種類近く設定されている環境を対応したので記録しておきます。
環境
サーバー
- OS:AlmaLinux9
- IMAP Server:Dovecot 2.3.16
- Mail User Agent:SnappyMail
クライアント
- OS:Windows 11
- Mail User Agent:Thunderbird 153.0
タグの仕様について
以前から SnappyMail(Web メール)で日本語タグが文字化けするとは思っていましたが、今回調べて違いがはっきりしました。
まず、SnappyMail は日本語のタグに対して、シンプルに MUTF-7 エンコードをして IMAP キーワードとして保存しています。
テスト ⇒ &MMYwuTDI-(MUTF-7 エンコード)
次に、Thunderbird 152.0.2 までメールの日本語タグは Modified UTF-7 でエンコードした後に小文字化して IMAP キーワードとして保存されていました。
テスト ⇒ &MMYwuTDI-(MUTF-7 エンコード)⇒ &mmywutdi-(小文字化)
Thunderbird 153 から MUTF-7 変換を廃止し、非 ASCII 文字・スペース・IMAP atom-special 文字を =XX 形式の hex エンコード(Modified Quoted-Printable)に置き換える方式に全面刷新されています。
テスト ⇒ =e3=83=86=e3=82=b9=e3=83=88(hex エンコード)
メールソフトごとに仕様が違うため、日本語のタグを使うのをやめて、英数字(スペースや記号無し)にすることにしました。
メールサーバーでの作業
件数が少なければ、タグを新しく設定し直して付け直すのも良いですが、数十万件のメールに 100 種類近いタグが付いている環境では現実的ではありません。
メールソフトからの操作はあきらめて、サーバー側の doveadm で一括置換することにしました。
リストアップ
全てのメールアカウントから、タグをリストアップしてファイルに書き出します。
#!/bin/bash
set -u
OUT='/tmp/kw-by-user.tsv'
: > "$OUT"
doveadm user '*' 2>/dev/null | while IFS= read -r u; do
doveadm mailbox list -u "$u" 2>/dev/null | while IFS= read -r box; do
printf 'a examine "%s"\na logout\n' "$box" \
| doveadm exec imap -u "$u" 2>/dev/null \
| grep -m1 '^\* FLAGS' \
| tr -d '\r' \
| sed 's/^\* FLAGS (//; s/)$//' \
| tr ' ' '\n'
done | grep -v '^\\' | grep -v '^$' | sort -u \
| awk -v u="$u" '{printf "%s\t%s\n", u, $0}'
done | tee "$OUT"/tmp/kw-by-user.tsv に全てのメールアドレスで使われているタグが出力されますので、これをダウンロードして置き換え用リストのベースとします。
小文字化された IMAP UTF-7 を復元するツール
旧 Thunderbird のキーワードは MUTF-7 を小文字化したものなので、Base64 部分の大文字小文字の情報が失われており、一意には復号できません。
そこで大文字小文字の組み合わせを総当たりでデコードし、日本語として成立する候補を列挙するツールを作成しました。
候補が複数出る場合もありますが、実際に使っていたタグ名なら見れば分かります。
タグを置換
#!/bin/bash
# 使い方: ./retag.sh ユーザー 旧キーワード 新キーワード
set -u
U=$1; OLD=$2; NEW=$3
echo "対象: $(doveadm search -u "$U" mailbox '*' keyword "$OLD" | wc -l) 件"
read -p "実行しますか? [y/N] " ans; [ "$ans" = y ] || exit 0
doveadm flags add -u "$U" "$NEW" mailbox '*' keyword "$OLD"
doveadm flags remove -u "$U" "$OLD" mailbox '*' keyword "$OLD"
echo "残存: $(doveadm search -u "$U" mailbox '*' keyword "$OLD" | wc -l) 件(0が正)"retag.sh に実行権限を付与します。
chmod +x retag.sh
./retag.sh shared@example.com '&mmywutdi-' 'test'タグを剥がす
#!/bin/bash
# 使い方: ./untag.sh ユーザー キーワード
set -u
U=$1; KW=$2
echo "対象: $(doveadm search -u "$U" mailbox '*' keyword "$KW" | wc -l) 件"
read -p "剥がしますか? [y/N] " ans; [ "$ans" = y ] || exit 0
doveadm flags remove -u "$U" "$KW" mailbox '*' keyword "$KW"
echo "残存: $(doveadm search -u "$U" mailbox '*' keyword "$KW" | wc -l) 件(0が正)"untag.sh に実行権限を付与します。
chmod +x untag.sh
./untag.sh shared@example.com '&mgywwtbo-'dovecot-keywords について
Dovecot(maildir)のキーワードは、フォルダごとの dovecot-keywords ファイルが「番号 ⇔ キーワード名」の対応表を持ち、メールのファイル名末尾の小文字 a〜z がその番号を指す仕組みです。
ファイル名に使える文字が 26 個しかないため、1 フォルダのキーワードが 26 個を超えると、27 個目以降は dovecot.index にのみ保存されます。
タグを全メッセージから剥がしても、dovecot-keywords の登録行と a〜z のスロットは残り続けます。
整理したい場合は、新しいフォルダを作成してメールを全件移動すると、移動先では実際に使われているキーワードだけで dovecot-keywords と index が再生成されるので、元のフォルダを削除して名前を付け替えれば完了です。
まとめ
Thunderbird 153 にアップデートすると、日本語タグが新しく付けられなくなったり、サーバー上の旧キーワードとの互換が失われたりします。
既存タグの移行処理がないため、日本語タグを使っていた環境では今回のような対応が必要になります。
日本語のタグは便利でしたが、複数クライアント環境では英数字だけで運用するのが無難だと痛感しました。

コメント