

CDIをアプリケーションから使う際にハマりがちな罠の説明。
スライドのそこかしこに登場する丸みを帯びたゆるDukeが可愛かった。
参加者20名くらい?懇親会前にジャンケン大会でMicroProfileのパーカーを頂いた。Lサイズを選んだがアメリカンのLサイズで、ゆったりだった。次回の勉強会に着て行く。
吉崎さんが追加の講演をしながら、懇親会も並行する感じでした。美味しくピザをいただきました。会場、懇親会の飲み物食べ物を提供してくださったレッドハットありがとう。
懇親会で私はずっと@_vermeer_と、AIを使った開発でシステム開発の人員は減らせそうだね、とか大規模開発では打ち合わせがボトルネックになりそうだけどもどういう流れで開発を進めていけばいいんだろうか、とか、MSX楽しいね、とか話していました。
Spring Bootに押され気味のJakarta EE。基幹システムでは古くから使われているが、今後どうなんだろうという感じ。Broadcom、VMwareの今後の以降が知れないので、Jakartaにも頑張って欲しいが、参加者も講演者もJakartaの今後はどうなんだろうね、とちょっと不安交じりでもありました。
あと、標準化されており実装は各々が出来る、とはいえコンポーネントによっては各メーカー同じ実装を使っているケースも多いので、標準化ってなんなんだろうね?とか、LibertyとWildfly/JBoss EAPはそろそろ合流しないのかね?とかも話題になりました。
いずれにせよ、選択肢が多いというJakarta EEのメリットはあるので今後の繁栄を願ってやみません。
IntelliJ IDEAであればCtrlを2回押して”gradlew wrapper --gradle-version=9.0.0“を入力すればOK。

無事ビルド、テスト実行できるか試してみたところ”Could not start Gradle Test Executor 2: Failed to load JUnit Platform. Please ensure that the JUnit Platform is available on the test runtime classpath.”と出て失敗しました。

問題の解決方法についてはURLが提示されていますが、エラーメッセージでもGradle 9: Failed to load JUnit Platform. Please ensure that the JUnit Platform is available on the test runtime classpath. #34512がヒットしました。どちらも同じことが書いてあって、
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
を追加すれば良いそうです。

というわけで、Gradle 9.0.0の新機能は何も活かしていないけれども無事テスト実行できるようになりました。

9.0.0にアップデートしたコミットはこちら。
サムライズムではこれまで3,4種類の仕様のバナーを試してみた経験から、旗・幕ドットコムの「ブルーバナーSS120」に落ち着いています。
・旗・幕ドットコム – 展示会ブース用バナースタンド – ブルーバナーSS120
価格はこの原稿を書いている時点で防炎加工付で2万円ほど。サイズ違いのバリエーションもあります。

組み立てが簡単で軽量、そして安定感と揃いも揃って間違いないです。
これまたいつもレビューを書いているくらいお気に入りです。
自動巻きのタイプは設置は簡単ですが少し重くれかさばること、収納時に歪んだ状態で巻かれるとバナーが破れたりシワが入ってしまったりすること、勢い良く巻かれると壊れてしまうことがある、など、実は扱いに少し気を使います。慣れない人が手を滑らして壊してしまうシーンをこれまで何度も見ています。
バナーを扱う人が固定されている場合は良いかもしれませんが、毎回誰が設置するか決まっていない会社では自動巻きタイプはオススメしません。
また、「ブルーバナーSS120」は、什器本体はそのままに、バナー部分だけど新たに印刷してもらって差し替えることも可能です。
自動巻きタイプのバナーの具の差し換えは多くの場合出来ません。
The post カンファレンスのスポンサーブース設営のお勧めアイテム その3 – バナー first appeared on yusuke.blog.]]>サムライズムでは
サイズ: 横3,000mm x 縦1,450mm
生地: バンテン(厚めの木綿生地)
防炎加工: あり
という仕様でハクロマーク製作所の旗・幕ドットコムでいつもお願いしています。
いつも一手間かけてレビューを送っているほど、抜群に信頼しています。対応もスムースで間違いないです。
・旗・幕ドットコム – 展示会用オリジナルテーブルクロスの印刷・作成
この仕様を、記事執筆時点で見積もると税別約5万円となります。後で説明するテーブルクロス止めも一緒に注文するのをお忘れ無く。
他の生地にすれば少し割安にもできますが、長持ちすること、見栄えや綺麗なこと、透けないことからバンテンがお勧めです。
薄い透ける生地で、後ろに窓があるとテーブル下に置いてあるバッグや備品が見えてしまうことがあります。
また、防炎加工のオプションもつけておきましょう。企業が開催する大きな会場ですと消防法の関係で防炎加工が必須となります。防炎加工は洗濯すると落ちてしまうので気を付けてください。
防炎効果の期間や、後から再度防炎加工できるか、など詳しい情報がハクロマーク製作所のYouTubeで解説されていますので合わせてご参照ください。
テーブルクロスはテーブルにかけるだけだと、端がダラっとしてしまいます。かならずテーブルクロス止めを使うようにしましょう。クロスがピッチリと箱形になって綺麗です。
Amazonやヨドバシでも買えます、ハクロマークならばテーブルクロス本体と一緒に注文出来ます。
・旗・幕ドットコム – テーブルクロス止め
テーブルクロス止めの使い方はこちら:
回数をこなす分、段々と運営用の物品が揃ってきましたのでお勧めの品物をアフィリエイトリンクを添えて書き連ねていきたいと思います。
まず最初は折りたたみコンテナ。
最初、展示用物品はダンボールに入れていましたが、2,3回も送るとボロボロになって穴が空いてきます。プラスチックの折りたたみコンテナならば何度も使えます。プラスチックだと衝撃でヒビが入ったり穴が空いたりするのでは?と心配があるかもしれませんが、比較的柔軟性のある素材なのでそう簡単には壊れません。たまーにネジが飛び出して来る事がありますが、プラスねじで軽く締めれば当面は大丈夫。
コンテナは蓋の継ぎ目を側面2箇所、上面1箇所、養生テープで止めれば輸送中に開いてしまうこともありません。養生テープは展示物をちょっと固定するとか、壊れた展示物を簡易補修するとか、何かと使います。まとめ買いしておきましょう。
・ダイヤテックス パイオラン 塗装・建築養生用テープ Y-09-CL 50mm×25m(5巻パック)

撤収時、養生テープでコンテナを閉じたところ養生テープを入れ忘れる、なんてことは良くあるのでお気をつけください。
先だってコンテナの幅に合わせて3本用意して、机に端っこだけ裏返して貼り付けておけばワシャワシャになりません。

また、養生テープはステッカー類がそこそこ剥がれやすい素材なので、上面に貼っておくと送り状などを綺麗に剥がすことが出来ます。

養生テープに貼られたステッカーを剥がすのはなかなかASMRです。
The post カンファレンスのスポンサーブース設営のお勧めアイテム その1 – 折りたたみコンテナ first appeared on yusuke.blog.]]>
docker stop squid-proxy;docker rm squid-proxy;docker run -d --name squid-proxy -p 3128:3128 sameersbn/squid:latest bash -c "\ apt-get update && \ apt-get install -y apache2-utils && \ htpasswd -b -c /etc/squid/passwords user1 password1 && \ chown proxy:proxy /etc/squid/passwords && \ chown proxy:proxy /dev/stdout && \ chmod 640 /etc/squid/passwords && \ echo 'http_port 3128 auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords auth_param basic realm Squid Proxy acl authenticated proxy_auth REQUIRED http_access allow authenticated access_log stdio:/proc/self/fd/1 squid cache_log stdio:/proc/self/fd/1 cache_store_log stdio:/proc/self/fd/1' > /etc/squid/squid.conf && \ squid -N"; docker logs -f squid-proxy
もちろん再現性を高めたり、細かく設定を変えたりするにはDockerファイルを作った方がいいです。
認証が要らない場合は以下で。
docker stop squid-proxy;docker rm squid-proxy;docker run -d --name squid-proxy -p 3128:3128 sameersbn/squid:latest bash -c "\ chown proxy:proxy /dev/stdout && \ echo 'http_port 3128 http_access allow all access_log stdio:/proc/self/fd/1 squid cache_log stdio:/proc/self/fd/1 cache_store_log stdio:/proc/self/fd/1' > /etc/squid/squid.conf && \ squid -N"; docker logs -f squid-proxyThe post ワンライナーで認証付のプロキシサーバをDockerとSquidで立てる first appeared on yusuke.blog.]]>
JavaMailでSMTPS/STARTLSを使う場合は “mail.smtp.ssl.checkserveridentity” を明示的に “true” に設定しましょう。デフォルトではホスト名検証されません。
JavaMailはJavaからメールの送受信を行うためのAPIです。
たとえば以下のようなコードでGMailのSMTPサーバを使ってメールを送信することができます。
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.UnsupportedEncodingException;
import java.util.Properties;
void main() throws MessagingException, UnsupportedEncodingException {
Properties props = getProperties();
Session session = Session.getInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("[email protected]", "password");
}
});
String encoding = "UTF-8";
MimeMessage mimeMessage = new MimeMessage(session);
mimeMessage.setHeader("Content-Type", STR."text/plain; charset=\{encoding}");
mimeMessage.setFrom(new InternetAddress("[email protected]", "[email protected]", encoding));
mimeMessage.setRecipients(Message.RecipientType.TO, new Address[]{new InternetAddress("[email protected]")});
mimeMessage.setRecipients(Message.RecipientType.CC, "[email protected]");
mimeMessage.setRecipients(Message.RecipientType.BCC
, new Address[]{new InternetAddress("[email protected]")});
mimeMessage.setReplyTo(new Address[]{new InternetAddress("[email protected]")});
mimeMessage.setSubject("件名", encoding);
mimeMessage.setText("本文", encoding);
mimeMessage.setHeader("Content-Transfer-Encoding", "7bit");
mimeMessage.setHeader("Content-Type", STR."text/plain; charset=\{encoding}");
Transport.send(mimeMessage);
}
private static Properties getProperties() {
Properties props = new Properties();
props.setProperty("mail.smtp.host", "smtp.gmail.com");
// SMTPS
// props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
// props.setProperty("mail.smtp.socketFactory.fallback", "false");
// props.setProperty("mail.smtp.port", "465");
// STARTTLS
props.setProperty("mail.smtp.port", "587");
props.put("mail.smtp.starttls.enable", "true");
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.smtp.ssl.checkserveridentity", "true");
props.setProperty("mail.debug", "true");
return props;
}
getPropertiesで設定している587はSTARTTLSという、セッション確立後にTLSを確立して安全性を確保する仕組みで使われるポート番号です。465番はセッション確立当初からTLS接続を行う場合に使います。
TLSの意義は暗号化することで盗聴から守ることに加えて、証明書を検証することで中間者/MITM攻撃を防ぐことにあります。つまり通信する相手が成りすましをしていないことを確認できます。
証明書の有効期限の切れたWebサイトや、ドメイン名を変えたのに別のドメインの証明書を使っているサイトなどにアクセスすると警告が出るのはそのせいです。
JavaMailは歴史のあるAPIで、SSLのサポートは後から追加されました。互換性維持のため、デフォルトではホスト名の検証を行わないそうです。
・Notes for use of SSL with JavaMail
なので、SMTPS/STARTTLSで接続する際は先のコード例のように
props.setProperty(“mail.smtp.ssl.checkserveridentity”, “true”);
と、”mail.smtp.ssl.checkserveridentity”プロパティを設定する必要があります。
設定しなくてもメールは送信できるし、サーバサイドで使われることの多いJavaアプリケーションにたいして中間者攻撃を実施できるケースは少ないです。が、可能性が低いこと=ホスト名検証をしなくて良いこと、にはなりません。
package one.cafebabe; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; public class Main { public static void main(String[] args) throws IOException { System.out.println("Java Version:" + System.getProperty("java.version")); String[] encodings = {"UTF-8", "SJIS"}; for (String encoding : encodings) { test(encoding); } } static void test(String encoding) throws IOException { System.out.println("---------Testing:" + encoding); Charset charset = Charset.forName(encoding); Path path = Path.of(encoding + "_encoded.txt"); String originalContent = "日本語です"; byte[] encodedBytes = originalContent.getBytes(charset); String decodedString = new String(encodedBytes, charset); System.out.println(decodedString); System.out.println("Decoded string matches:" + decodedString.equals(originalContent)); Files.writeString(path, originalContent, charset); String read = Files.readString(path, charset); System.out.println(read); boolean matches = read.equals(originalContent); System.out.println("Content from file matches:" + matches); } }
“日本語です”という文字列をShift_JISでファイルに書き出し、読み込むだけです。
Java 22だと実行結果が以下のようになります。バイト列で書き出して、new String()で復元した場合は問題ありませんが、Files.readStringで読み込んだ場合は化けているのが分かります。
Java Version:22 日本語です Decoded string matches:true åe,gg0Y0 Content from file matches:false
“日本語です”という文字列をShift_JISでファイルに書き出し、読み込むだけです。
Java 21は以下のように化けません。
Java Version:21.0.2 日本語です Decoded string matches:true 日本語です Content from file matches:true
Java 22は長期サポート版(LTS)ではないので、移行する人は多くないと思いますが、日本で広く使われるエンコーディングなのでご利用になる方はご注意ください。UTF-8エンコーディングの読み込みでは文字化けしません。また、Shift_JIS以外については確認していません。
根本原因について調査はしません。興味のある方は是非追ってみてください。
この現象は既にbugreport.java.comへ報告済みです。
確認したところShift_JISに限らず、UTF-8以外の多くのエンコーディングで文字化けするようです。
さらに確認したところ、InputStreamReaderを使った場合は化けず、Files#readStringを使った場合に化けることも分かりました。new String()で化けていなかったことからそこまで心配していませんでしたが、コアライブラリ全般に渡るバグではなくて、ピンポイントにFiles#readStringの問題かもしれませんね。

追記:
バグ登録されました。
JDK-8328714 : Shift_JIS encoded content gets garbled with Java 22
追記:
Oracleから返事があり、リリースノートに記載の既知の問題であるとのことです。リリースノートを確認するのは基本ですね。お恥ずかしい!しかしこんな問題がテストで検出されず、既知の問題として認識されたままリリースされるとは想像していませんでした……。というわけで、リリースノートに記載の通り、-XX:-CompactStrings オプションをつけることで回避が出来ることを確認しました。ちなみに@skrbにより指摘していただいた件がビンゴでした(この修正がリグレッションを産んだのでは?という予想だったみたいですが、まだ取り込まれていなかったようです)。

メールを配信する仕組みは当初性善説に基づいて設計されたため、送信元や時刻を偽ったり、途中で文面が改善されていたりしても検証する仕組みがありませんでした。
現在はSPF、DKIM、DMARCといった技術で、送信元の詐称や改竄を防ぐことが出来るようになっており、これらの設定をしていないと迷惑メールとして弾かれたり、受信が拒否されたりといったことが起こりやすくなります。
中でもSPFは最低限設定しておかないと簡単に迷惑メールに振り分けられます。
SPF、DKIM、DMARCについて詳しくは世の中にいくらでも解説がありますが、自分の理解のために簡単にまとめました。
第三者が勝手なサーバからメールを配信したものを検出できるようにする仕組み。
紫外線をどれくらい防げるかの度合い、”Sun Protection Factor”、とは別で”Sender Policy Framework”の略。特定のドメインのメールがどのサーバから配信されるのかをDNSで事前に設定しておく。
ドメインで事前に設定されていないサーバから送られてくるメールは詐欺だろうと検出できる。
設定はdigコマンドでTXTレコードを引くと確認できる。
% dig samuraism.com TXT <略> samuraism.com. 300 IN TXT "v=spf1 include:_spf.google.com include:mail.zendesk.com ~all"
この例では具体的な送信サーバはGoogleやZendeskが設定しているものを引用するようになっている。
メールの改竄を検出する仕組み。
送信元でメール内容を秘密鍵を使って署名を生成し、ヘッダ “Dkim-Signature”に記し、受信者はDNSから公開鍵を取得して署名を検出することで改竄を検出できる。
秘密鍵、公開鍵は以下のようなopensslコマンドで生成できる。
% openssl genrsa -out private.pem 2048 % openssl rsa -in private.pem -out public.pem -pubout -outform PEM
公開鍵(public.pem)—–BEGIN PUBLIC KEY—– / —–END PUBLIC KEY—–を除く部分を[セレクタ]._domainkey.[ドメイン]というTXTレコードに設定する。
DNSのレコードは255文字を超える場合は以下のように、255文字以内に区切ってダブルクオートで囲い、スペースで区切った形で設定する必要がある。
“255文字までの文字列1” “255文字までの文字列2”
設定した公開鍵は、例えば鍵のセレクタがgmaildkim、ドメインがsamuraism.comであれば以下のdigコマンドで確認できる。
dig gmaildkim._domainkey.samuraism.com TXT
覚書をまとめるまでも無くSendGrid/構造計画研究所のページを見るのが一番!
SendGrid ユーザマニュアル > Domain Authentication(SPF/DKIM設定)の設定方法
DNSレコードさえ正しく指定しておけば、SendGridのSMTPサーバが署名を行ってくれるので、アプリケーションでDkim-Signatureヘッダを指定する必要はありません。
メール回りの疑問は構造計画研究所のサイトを見れば間違いなく解決します。
Google Workspaceの管理画面の[アプリ>Gmail>メールの認証]から設定する。

「新しいレコードを生成」を押して表示される「新しいレコードを生成」ダイアログで、DKIMの鍵長(現在は2048ビットが推奨されるらしい)を選び、任意のプレフィックス(セレクタ)を指定して生成する。

生成された鍵をDNSで指定(255文字を超えているのでダブルクオートやスペースで区切る必要がある)して、「認証を開始」を押すと有効になる。
Gmailから送るメールも、アプリケーションからGoogleのSMTPサーバ smtp.gmail.com を使って送る場合も自動的に署名(Dkim-Signature)が付加されるようになります。
つまりアプリケーションでDkim-Signatureヘッダを生成/設定する必要はありません。
zendesk1._domainkey.[ドメイン名] → zendesk1._domainkey.zendesk.com
zendesk2._domainkey.[ドメイン名] → zendesk2._domainkey.zendesk.com
というCNAMEレコードを設定する。
管理画面の[Talkとメール>メールアドレス>DKIMのカスタムドメイン>有効にする]にチェックを入れる。
・Zendesk – DKIMを使用したメールのデジタル署名
DKIM Record Checkerでドメインとセレクタ名を入れてチェックできる。

DMARCはメールの認証に失敗した場合にどのように処理するか(none:なにもしない、quarantine:隔離する≒迷惑メールフォルダに振り分けられる、reject:受信を拒否する)を指定したり、認証に失敗した集計レポートを送るメールアドレスの送信先を指定したりできる。
DMARCはDNSに _dmarc.[ドメイン名] というTXTレコードで設定する。
digコマンドではこう確認する
% dig txt _dmarc.samuraism.com ; <<>> DiG 9.10.6 <<>> txt _dmarc.samuraism.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32891 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;_dmarc.samuraism.com. IN TXT ;; ANSWER SECTION: _dmarc.samuraism.com. 3600 IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]; pct=20" ;; Query time: 78 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Thu Jan 18 18:08:08 JST 2024 ;; MSG SIZE rcvd: 132
この場合は p= で、認証に失敗した場合は隔離、rua= で集計レポートは[email protected]に送信、pct= でDMARCによる認証は全体の20%に適用、という設定になっている。
pctは1〜100(%)を指定でき、何も指定しない場合はデフォルトの100が適用される。設定に問題があり、メールが拒絶されまくってしまうような事態を防ぎたければ低い値を設定し、最終的に100か、指定なしにする。
DMARC Record Checkerで確認できる。

これはあくまでDNSレコードの設定内容を確認するだけで、SPFやDKIMが適用されてメールが正しく認証されていることを確認しているわけではない。
メールを外部に送信し、Authentication-Resultsヘッダを見る。
SPF、DKIM、DMARC、それぞれ検証に成功していれば以下のように spf=pass、dkim=pass、dmarc=passと書かれている。
Authentication-Results: bimi.icloud.com; bimi=skipped reason="insufficient dmarc" Authentication-Results: arc.icloud.com; arc=none Authentication-Results: dmarc.icloud.com; dmarc=pass header.from=samuraism.com Authentication-Results: dkim-verifier.icloud.com; dkim=pass (2048-bit key) header.d=samuraism.com [email protected] header.b=Q9wPckpv Authentication-Results: spf.icloud.com; spf=pass (spf.icloud.com: domain of [email protected] designates 209.85.210.45 as permitted sender) [email protected]
また、Dkim-Signatureヘッダの d= にfromアドレスのドメインが記載されていることも確認。つまりFrom:[email protected]であれば d=samuraism.com となっているべき。
Dkim-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samuraism.com; s=gmaildkim;
d=のドメインがGoogleとかZendeskとかのドメインになっている場合はfromアドレスのドメインの保有者が作成したメールとは判断できない「第三者認証」と呼ばれる物になる。改竄されていないことは検証できるが、ドメインを所有している人からのメールだとは検証できない状態。
mail testerでは、送られたメールを検証して10点満点でスコアをつけてくれます。
トップページを開くと、先方が検証に使うための専用のメールアドレスを用意してくれているので、メールを送ります。
メール文面もスコアリングの対象なので、(個人情報をマスクなどした上で)実際にシステムから送られる文面を使いましょう。

メールを送ったら”Then check your score”を押すと、スコアをつけてくれます。DMARCはスコアの対象外ですが、SPFとDKIMIについては見てくれているようです。
何が問題でスコアが下がっているかも表示されます。改善を施した上で、同じメールアドレスに再送したら、再度スコアをつけて貰うことも出来ます。

先のAuthentication-Resultsヘッダに”insufficient dmarc”という文字列があってドキッとさせますが、これはBrand Indicators for Message Identificationという、メール送信者のブランドロゴを表示させる、いわばメール版のfaviconみたいな仕組みの仕様を満たしていないよ、という意味です。
例えば楽天はグループ全体で対応させているようで、以下のようにメーラで確認ができます。分かりやすくていいですね!

default._bimiというDNSレコードで設定状況を確認できます:
% dig default._bimi.rakuten.com TXT ; <<>> DiG 9.10.6 <<>> default._bimi.rakuten.com TXT ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31023 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;default._bimi.rakuten.com. IN TXT ;; ANSWER SECTION: default._bimi.rakuten.com. 21600 IN TXT "v=BIMI1; l=https://r.r10s.jp/com/bimi/r_crimsonred/r_crimsonred.svg;a=https://r.r10s.jp/com/bimi/r_crimsonred/r_crimsonred_177085657.pem;" ;; Query time: 39 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Fri Jan 19 13:34:12 JST 2024 ;; MSG SIZE rcvd: 204
Gmailでも表示させるには、VMCという仕組みを利用するために年間数十万の費用をかけて認証してもらう必要があるようです。
自分の会社で送るのはほぼトランザクションメールで、受信者は読む動機があるので今のところはいいかな、と思っています。
マーケティングメールを頻繁に送る組織ではお金をかけてBIMIに対応させるのもいいかもしれません。
type="email"のinputで、requiredの代わりにmultipleと記載しておくとメールアドレスをスペース区切りまたはカンマ区切りで複数指定してもらうことが可能です。
何も入力がない場合、または正しいメールアドレスが複数並んでいる場合にvalidと判定されます。CCメールアドレスを指定して貰う欄なんかは良いですね。requiredと合わせて指定することで「1つ以上」のメールアドレスを入力必須とすることも出来ます。
また、:invalid疑似クラスを使うことで必須項目が入力されていない際のスタイルを指定することもできます。
JavaScriptで.required=true/falseとすれば動的に入力必須/不要をトグルすることもできます。
ただし、HTML要素的には属性の存在の有無で入力の要/不要が決まるため、required=”false”と書いても入力不要にはなりません。
また、技術的に入力漏れを確実に防ぐものではありません。古いブラウザや、機械的な手段で入力が漏れる可能性はあるため、ロジック上必要な項目についてはサーバサイドでのチェックは引き続き必要です。

動作をざっと把握できるコードは以下のようになります。
<style>input:invalid{background-color:#ffebeb;}</style>
<form>
<label for="name">名前</label><input type="text" id="name" name="name"/>
<label for="email">メールアドレス</label><input type="email" id="email" name="email" required/>
<label for="emailmulti">メールアドレス(複数)</label><input type="email" id="emailmulti" name="emailmulti" multiple/>
<input type="submit" value="送信"/>
</form>
<button onclick="document.getElementById('name').required=true">名前を入力必須にする</button>
<button onclick="document.getElementById('name').required=false">名前を入力必須では無くする</button>
動作するサンプル:
The post required属性で入力必須項目のチェックをブラウザに行わせる first appeared on yusuke.blog.]]>