Gandi.net の無料メールで DMARC を設定してみる

ふと、新しいドメインを衝動買いしてしまいました。 .dev ドメインです。取得費用 1759円で安かった(更新料も同額)。運用中の汎用 .jp ドメインの半額です。レジストラは Gandi.net を選びました。フランスの企業ですが、日本語サイトがちゃんとあって、手続きは全部日本語でできます。支払いも日本円で OK (クレカか PayPal)。ただし、マニュアルとかドキュメントは英語です。英語読めないひとにはオススメしません。追加費用なしで Whois 情報の保護(ドメイン所有者とかの個人情報を隠してくれる)もやってくれるので、安心です。

Gandi.net で独自ドメインを取得すると、無料でメールサービスが付いてきます。メールボックスは2個までですが(課金すれば増やせる)、エイリアスを無制限に使える(しかもワイルドカード指定ができる)ので、使いやすいです。デフォルトで SPF と DKIM が設定されているので、スパム扱いされるリスクも低いです。すばらしい。

せっかくなので、よりメールの安全性を高めるべく、DMARC も設定してみることにしました。

DMARC の設定というのは、実際のところ、DNS サーバの設定に TXT レコードを1個追加するだけです。簡単。

ちなみに、 SPF は “Sender Policy Framework” の略、 DKIM は “DomainKeys Identified Mail” の略、 DMARC は “Domain-based Message Authentication, Reporting & Conformance” の略です。

手順

前提条件として、Gandi.net のメールサービスを使って正常にメール送信できることを確認しておく必要があります。 SPF と DKIM の設定が正しく動作していなければなりません。独自ドメインのメールアドレスから、自分のプロバイダのメールアドレスとか Gmail とかにメールを送信してみて、届いたメールのメールヘッダの中身をチェックします。具体的には、Authentication-Results: ヘッダの値に dkim=passspf=pass という文字列が含まれていることを確認します。もし、dkim=fail とか spf=softfail とか書いてあったらダメです。ちなみに、順不同です(メールサーバによって書かれている順番が異なる)。

今回試した限りでは Gandi.net のデフォルト設定で問題なかったので、ダメだった場合は、自分でなにか設定を変えてしまったか、Gandi.net のメールサーバの設定が変わってしまったのか、いずれにしてもがんばって解決してください。

さて、SPF と DKIM の設定に問題が無いことが確認できたら、DMARC の設定をしてみます。具体的には、Gandi.net で運用してもらっている DNS サーバの設定を変更することになります(DMARC の設定を追加します)。

Gandi.net にログインして、DNS サーバの設定(「DNSレコード」)を開きます。

レコード一覧を見ると、SPF と DKIM については最初から設定されていることがわかります。

ここにひとつ、TXT レコードを追加してあげます。ページ右上の「レコードを追加」ボタンを押すと「DNSレコードを追加」画面が開くので、テキストを入力します。「タイプ」は TXT を選択します。「レコード名」には _dmarc と入力します。「テキスト値」には DMARC の設定を書きます。書き方は上記の DMARC 関連リンクを参考にしてください。下記スクリーンショットは、あくまでも Seaoak のドメインの設定例なので、そのまま同じ設定を入力してはいけません。少なくとも rua フィールドの値は自分のドメインのメールアドレスに変える必要があります。

TTL とそのユニットについては、変えなくていいハズ(設定を間違えた場合を考えると短くしたほうがいいのかしら?)。入力できたら、最後に「設定」ボタンを押すと、即座に DNS サーバの設定が更新されます。 DNS レコード一覧を見ると、ちゃんと _dmarc の行が追加されていることが確認できます。

ためしに、手元の Windows PC で DNS を引いてみます。 Windows に最初から入っている nslookup コマンドを使います。 TXT レコードを指定するために set type=txt と入力して、それから _dmarc.ドメイン名 と入力すると、上で設定した DMARC レコードが表示されるハズです。

もし、「~を見つけられません: Non-existent domain」とか言われてしまった場合は、独自ドメインの DNS 情報がどこかの DNS サーバにキャッシュされてしまっています。 Gandi.net の DNS サーバ(権威サーバ)に設定した情報が反映されるまでしばらく時間をおいてから、再実行してみましょう。最悪でも翌日になれば変更が反映されるハズです。

nslookup コマンドで確認できたら、忘れずに、DMARC の分析レポート (rua) の宛先に指定したメールアドレスで、ちゃんとメールを受信できるようにしておきます。 Gandi.net のメールボックスのエイリアスに dmarc* とか指定しておけば OK でしょう。ちなみに、送られてくる分析レポートメールには .zip ファイルが添付されていて、その中身は XML テキストです。人間には解読できないので、てきとうなクラウドサービスとかを使うのが良さそうですね。

最後に、DMARC の動作確認をします。独自ドメインのメールアドレスから(Gandi.net のメールサービスを使って) Gmail とかにメールを送信してみます。そのメールが無事に受信できたら、受信したメールのメールヘッダをチェックします。 Authentication-Results: ヘッダの値に dmarc=pass という文字列が含まれていれば成功です。このとき、spf=passdkim=pass も含まれているハズです。

以上で、DMARC の導入ができました。おつかれさまでした。

今後のアクション

せっかく設定した DMARC ですが、実は、上記の DMARC 設定では p=none という記述になっているので、「SPF / DKIM の認証でエラーになったメールもそのまま正常なメールとして受信してください」という指定(受信サーバへの依頼)になっています。つまり、実質的にはメールセキュリティは強化できていません。あくまでも認証エラーが発生しているかどうかのレポートが得られる(送られてくる)だけです。

そこで、次のステップとしては、DMARC ポリシーを「SPF / DKIM の認証でエラーになったメールは『不審なメール』扱いしてください」という指定に変えたいです。具体的には、DMARC レコードの値で p=none としているのを p=quarantine に書き替えます。これにより、送信元を偽装したメールは、受信メールボックスで「迷惑メール」に振り分けられるようになります(正確には、その可能性が高くなります)。

さらにメールのセキュリティを強化するならば、DMARC レコードで p=reject と書きたいところです。この指定をすることで、送信元を偽装したメールは受信サーバで破棄してもらえるようになります(そのように受信サーバに依頼している形になります)。

まぁ、新規ドメインならば、既存のメールサーバが存在していて SPF や DKIM に対応できていない、という問題は無いので、いきなりこの p=reject 設定にしてしまっても大丈夫かもしれません。ただし、自分の管理するクラウドサーバとかから独自ドメインのメールアドレスを差出人にしてメールを送信する、ということができなくなりますので、ご注意ください(送信元の偽装と判断されてしまいます)。

おまけ: .dev ドメインについて

ちなみに蛇足ですが、今回 .dev ドメインを選んだのは、ドメイン丸ごと HSTS が設定されていてセキュリティを重視している点が好みだったからです(HSTS というのは、HTTP 接続しようとするとブラウザが強制的に HTTPS 接続に切り替えてくれるしくみです)。正直、.io ドメインとどちらにするか迷ったのですが、費用が .io ドメインの半額以下ですし、 2文字 TLD (国や地域に割り振られている TLD)は管理体制に不安があるなんて噂もあるので、.dev ドメインにしました。なお、HSTS が設定されている副作用として、Gandi.net がデフォルトで提供しているウェブリダイレクト機能を使えない、というデメリットもあります(HTTPS 接続をリダイレクトするためにはリダイレクトサーバに SSL サーバ証明書が必要になるからですね)。

PNG に代わるロスレス圧縮の画像フォーマットをさがす

データバックアップ用に 8TB ハードディスクを買ったので、ローカルディスクのフルバックアップをとったのですが、コピーツール (FastCopy) の画面を見ていて、あらためて「PNG ファイルがたくさんあるなぁ」と思い、「もしかして WebP とか新しいフォーマットならもっと小さくなるのでは?」とひらめいて、ちょっと調べてみました。

結論としては、PNG をやめて WebP に移行することにしました。

ちなみに、その大量の PNG ファイルは、オンラインゲーム FINAL FANTASY XIV (FF14) のスクリーンショットだったりします。撮影には Bandicam を使っていて、BMP 形式で保存するようにしています(その場で PNG 圧縮すると連写ができなさそうなので)。その BMP ファイルを、定期的に ImageMagick で PNG ファイルに変換(圧縮)しています。シェルスクリプトで一括変換。 FF14 は2013年からプレイしているので、現時点で 6.5万ファイルあって、総サイズは 412GB になります。 4K 解像度でプレイしているので、サイズがでかいです。もちろん、非可逆圧縮の JPEG とかにしちゃえばもっと小さくなるのはわかっているのですが、スクリーンショットは「思い出の記録」なのでロスレスは譲れないのでした。

はじめに

今回の調査の目的は、静止画イメージファイルのロスレス圧縮フォーマットで、PNG に代わる新しいものを探す、というものです。扱う画像は「3D オンラインゲームのスクリーンショット」です。 4K (3840x2160) 解像度で、RGB 各 8bit (アルファチャネルなし)の画像です。 一般の「写真」や「イラスト」や「文書」や「スライド」などでは異なる結果になる可能性があります

実験に使った画像は、BMP 形式で 23MB のものです。

original PNG file (10MB)

前提条件:

  • Windows 10 で使えること。
  • 画像ビューアー XnView MP で閲覧&サムネイル生成ができること。
  • 画像編集ソフト GIMP で読み書きできること。
  • できれば、コマンドラインから実行できるとうれしい(シェルスクリプトで一括変換したい)。

実行環境:

OS: Windows 10 Pro 64bit 21H2 (build 19044)
CPU: AMD Ryzen Threadripper 2950X (16core/32thread, 3.5GHz)
MEM: 32GB DDR4-3600
SSD: Intel 760p (2TB)

ImageMagick のバージョンは 7.1.0-26 Q16-HDRI x64 2022-02-21 (の Portable 版)です:

$ convert -version
Version: ImageMagick 7.1.0-26 Q16-HDRI x64 2022-02-21 https://imagemagick.org
Copyright: (C) 1999-2021 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenCL
Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib
Compiler: Visual Studio 2022 (193030709)
$

ちゃんと「ロスレス」圧縮になっているかの確認には、ImageMagick の compare コマンドを使います。メトリクス AE を指定して、ピクセル単位で一致しない箇所を数えてもらいます。出力が 0 なら、完全一致(=ロスレス)ということになります。

$ compare -metric AE aaa.bmp aaa.png NULL:
0
$
$ compare -metric AE aaa.bmp aaa.jpg NULL:
7.97697e+06
$

参考情報にしたサイト:

WebP をためしてみる

WebP は、Google が開発した画像フォーマットで、動画圧縮コーデック VP8 の技術を利用して圧縮するものです。

まずは、なにもオプションを指定せずに ImageMagick で変換してみる:

$ convert aaa.bmp aaa.webp

ロスレスかどうか、チェックをしてみる:

$ compare -metric AE aaa.bmp aaa.webp NULL:
8.20354e+06
$

デフォルトではロスレス圧縮にならない模様。

今度は明示的にロスレス圧縮の指定してみる:

$ time convert aaa.bmp -define webp:lossless=true ccc.webp

real    0m7.564s
user    0m0.000s
sys     0m0.015s
$
$ du -sk aaa.png ccc.webp
9964    aaa.png
7448    ccc.webp
$
$ compare -metric AE aaa.bmp ccc.webp NULL:
0
$

ちゃんとロスレス圧縮になりました。PNG 形式に比べてファイルサイズが 76% に小さくなっていますね。優秀!

なお、WebP に変換する際に -quality 99 とか指定してみても、ファイルサイズの差はわずかでした:

$ time convert aaa.bmp -quality 99 -define webp:lossless=true ddd.webp

real    0m8.778s
user    0m0.015s
sys     0m0.016s
$
$ du -sk aaa.png ccc.webp ddd.webp
9964    aaa.png
7448    ccc.webp
7344    ddd.webp
$

AVIF をためしてみる

AVIF (AV1 Image File Format) は、動画圧縮コーデック VP1 の技術を使って圧縮する画像フォーマットです。

まずは ImageMagick を使って変換してみます。

$ time convert aaa.bmp -quality 100 ccc.avif

real    0m24.906s
user    0m0.000s
sys     0m0.015s
$
$ du -sk ccc.avif
4816    ccc.avif
$
$ compare -metric AE aaa.bmp ccc.avif NULL:
7.13956e+06
$

-quality 100 を指定してもロスレスにならない・・・。

ImageMagick をあきらめて、libavif の avifenc.exe を試してみることにします。

最新の v0.9.0 をダウンロードして使いました。

$ ~/Downloads/libavif/v0.9.0/avifenc.exe --version
Version: 0.9.0 (dav1d [dec]:0.8.2-0-gf06148e, aom [enc/dec]:2.0.2)
libyuv : unavailable

$

avifenc.exe --help で確認すると .bmp ファイルは直接食べられないみたいなので、.png ファイルを入力ファイルとして指定します。

$ time avifenc.exe --lossless aaa.png ccc.avif
Successfully loaded: aaa.png
AVIF to be written: (Lossless)
 * Resolution     : 3840x2160
 * Bit Depth      : 8
 * Format         : YUV444
 * Alpha          : Not premultiplied
 * Range          : Full
 * Color Primaries: 1
 * Transfer Char. : 13
 * Matrix Coeffs. : 0
 * ICC Profile    : Absent (0 bytes)
 * XMP Metadata   : Absent (0 bytes)
 * EXIF Metadata  : Absent (0 bytes)
 * Transformations: None
Encoding with AV1 codec 'aom' speed [6], color QP [0 (Lossless) <-> 0 (Lossless)], alpha QP [0 (Lossless) <-> 0 (Lossless)], tileRowsLog2 [0], tileColsLog2 [0], 1 worker thread(s), please wait...
Encoded successfully.
 * Color AV1 total size: 10888940 bytes
 * Alpha AV1 total size: 0 bytes
Wrote AVIF: ccc.avif

real    3m2.572s
user    0m0.000s
sys     0m0.031s
$
$ du -sk aaa.png ccc.avif
9964    aaa.png
10636   ccc.avif
$
$ /c/OnlineSoftware/ImageMagick/compare.exe -metric AE aaa.bmp ccc.avif NULL:
0
$

無事にロスレスの AVIF ファイルができましたが、ファイルサイズが PNG より大きい・・・。

ためしに一番遅い --speed 0 を指定してみる。

$ time avifenc.exe --lossless --speed 0 aaa.png ccc.avif
Successfully loaded: aaa.png
AVIF to be written: (Lossless)
 * Resolution     : 3840x2160
 * Bit Depth      : 8
 * Format         : YUV444
 * Alpha          : Not premultiplied
 * Range          : Full
 * Color Primaries: 1
 * Transfer Char. : 13
 * Matrix Coeffs. : 0
 * ICC Profile    : Absent (0 bytes)
 * XMP Metadata   : Absent (0 bytes)
 * EXIF Metadata  : Absent (0 bytes)
 * Transformations: None
Encoding with AV1 codec 'aom' speed [0], color QP [0 (Lossless) <-> 0 (Lossless)], alpha QP [0 (Lossless) <-> 0 (Lossless)], tileRowsLog2 [0], tileColsLog2 [0], 1 worker thread(s), please wait...
Encoded successfully.
 * Color AV1 total size: 10884272 bytes
 * Alpha AV1 total size: 0 bytes
Wrote AVIF: ccc.avif

real    10m30.801s
user    0m0.000s
sys     0m0.015s
$
$ du -sk aaa.png ccc.avif
9964    aaa.png
10632   ccc.avif
$
$ compare -metric AE aaa.bmp ccc.avif NULL:
0
$

1ファイルの変換に10分もかかったけど、ファイルサイズはほとんど変わらなかった。残念。

JPEG XL をためしてみる

JPEG 後継の JPEG XL は、その名に反して(?)、ロスレス圧縮もサポートしてます。

とりあえず ImageMagick でロスレス圧縮を指定する方法がわからなかったので、libjxl の cjxl.exe を使うことにしました。最新の v0.6.1 の jxl-x64-windows-static.zip をダウンロードして使います。

$ time cjxl.exe aaa.png ddd.jxl -q 100 -v
JPEG XL encoder v0.6.1 a205468 [AVX2,SSE4,Scalar]
Read 3840x2160 image, 31.1 MP/s
Encoding [Modular, lossless, squirrel], 16 threads.
Compressed to 7085947 bytes (6.834 bpp).
3840 x 2160, 0.29 MP/s [0.29, 0.29], 1 reps, 16 threads.
Average butteraugli iters:       0.00
Total layer bits headers          0.000192%       109
Total layer bits TOC              0.005866%      3325
Total layer bits quant tables     0.000002%         1
Total layer bits modularGlobal    0.229026%    129828   [c/i:128.00 | hst:   16223 | ex:       0 | h+c+e: 6837135.182]
Total layer bits modularAcGroup  99.496368%  56401504
Total layer bits modularTree      0.268547%    152231   [c/i:  4.00 | hst:      54 | ex:     893 | h+c+e:   18948.540]
Total image size             56686998   [c/i:132.00 | hst:   16278 | ex:  249837 | h+c+e: 7105027.598]
Allocations: 1132 (max bytes in use: 4.223050E+08)

real    0m29.137s
user    0m0.000s
sys     0m0.031s
$
$ du -sk aaa.png ddd.jxl
9964    aaa.png
6920    ddd.jxl
$
$ compare -metric AE aaa.bmp ddd.jxl NULL:
0
$

無事にロスレス圧縮ができました。ファイルサイズが WebP よりさらに小さいですね。ただ、遅いです。

さらに effort を max 指定にしてみます:

$ time cjxl.exe aaa.png eee.jxl -q 100 -v -e 9
JPEG XL encoder v0.6.1 a205468 [AVX2,SSE4,Scalar]
Read 3840x2160 image, 31.4 MP/s
Encoding [Modular, lossless, tortoise], 16 threads.
Compressed to 6882664 bytes (6.638 bpp).
3840 x 2160, 0.02 MP/s [0.02, 0.02], 1 reps, 16 threads.
Average butteraugli iters:       0.00
Total layer bits headers          0.000198%       109
Total layer bits TOC              0.005995%      3301
Total layer bits quant tables     0.000002%         1
Total layer bits modularGlobal    0.316592%    174318   [c/i:126.00 | hst:   21785 | ex:       0 | h+c+e: 6661939.822]
Total layer bits modularAcGroup  99.085528%  54557192
Total layer bits modularTree      0.591685%    325786   [c/i:  4.00 | hst:     131 | ex:    1751 | h+c+e:   38462.166]
Total image size             55060707   [c/i:130.00 | hst:   21916 | ex:  142402 | h+c+e: 6841052.863]
Allocations: 1132 (max bytes in use: 4.222756E+08)

real    6m5.410s
user    0m0.000s
sys     0m0.015s
local:/i/FF14/images/00_NEW $ du -sk aaa.png eee.jxl
9964    aaa.png
6724    eee.jxl
$
$ compare -metric AE aaa.bmp eee.jxl NULL:
0
$

さらに 3% ほどファイルサイズが小さくなりましたが、実行時間が10倍以上に延びてしまいました。コスパ悪い。

ImageMagick でも -quality 100 指定でロスレス圧縮になる、との情報をいただいたので、試してみる:
(thanks @yoya)
https://twitter.com/yoya/status/1496499554107404288

$ time convert aaa.bmp -quality 100 fff.jxl

real    12m45.754s
user    0m0.015s
sys     0m0.000s
$
$ du -sk aaa.bmp *.jxl
24304   aaa.bmp
6920    ddd.jxl
6724    eee.jxl
12548   fff.jxl
$
$ compare -metric AE aaa.bmp fff.jxl NULL:
28697
$

すごく時間がかかった上に、微妙にロスレスになってくれなかった。残念。

BPG をためしてみる

BPG (Better Portable Graphics) 形式というものがあったので、ためしてみます。

ImageMagick は BPG 形式をサポートしていないみたいです。

最新の v0.9.8 の win64 版 bpg-0.9.8-win64.zip をダウンロードして使います。

bpgenc.exe -h で確認すると .jpg か .png しか食べられないみたいなので、.png ファイルを指定します。

$ time ~/Downloads/bpg/bpg-0.9.8-win64/bpgenc.exe -o ddd.bpg -c rgb -lossless aaa.png

real    0m2.624s
user    0m0.015s
sys     0m0.000s
$
$ du -sk aaa.png ddd.bpg
9964    aaa.png
11048   ddd.bpg
$
$ ~/Downloads/bpg/bpg-0.9.8-win64/bpgdec.exe -o ddd.bpg.png ddd.bpg
$
$ compare -metric AE aaa.bmp ddd.bpg.png NULL:
0
$

無事にロスレス圧縮ができましたが、PNG 形式よりファイルサイズが大きくなってしまいました。

ためしに、compression level を slowest にしてみる:

$ time ~/Downloads/bpg/bpg-0.9.8-win64/bpgenc.exe -o eee.bpg -c rgb -lossless -m 9 aaa.png

real    0m2.722s
user    0m0.000s
sys     0m0.015s
$
$ du -sk aaa.png eee.bpg ddd.bpg
9964    aaa.png
11048   eee.bpg
11048   ddd.bpg
$

結果は変わらず。残念。

まとめ

実験の結果をまとめると、次の表のようになります:

圧縮率は 28% の JPEG-XL が一番いいけど、次点の WebP も 31% と優秀。そして WebP は実行時間が 7 秒半と短い(JPEG-XL は 29 秒もかかっている)。

最後に、たくさんのファイルでの試験もやってみます。 2020年2月に撮ったスクリーンショット 463 枚(約 11GB)の BMP ファイルを、32 プロセス並列で(xargs -P 32 を使って)一括変換してみました。

WebP の結果が優秀ですね。

あと、JPEG XL 形式に変換したフォルダを画像ビューアー XnView MP で開いてみると、サムネイル作成がめちゃめちゃ遅いことが判明しました。かなり不便です。

結論として、WebP を採用することにしました。