電話番号・Wi-Fi・メールのQRコードをURIスキームで作る仕組み(tel:/WIFI:/mailto: とqrcode.js)

QRコードは「特別なアプリ」を作らなくても、埋め込む文字列(URIスキーム)を正しく組み立てるだけで多くの挙動を実現できる。QRコードはただの文字列エンコーダで、読み取り側のOS/アプリがその文字列を解釈して動く。以前 SMS・位置情報QRの記事SMSTO:geo: を扱ったが、今回は運用中のツールサイト「ハシトシステム」に追加した 電話番号QR と、既存の Wi-Fi QRメールQR を題材に、tel: / WIFI: / mailto: の組み立て方を整理する。どれも入力からQR生成まで完全にブラウザ内(クライアント)で完結し、入力内容をサーバーに送らない。

3つのURIスキームの形

それぞれ文字列の形はこうだ。

  • 電話番号: tel:0312345678 — 数字(と先頭の +)だけ。ハイフンや空白は取り除く。
  • メール: mailto:info@example.com?subject=...&body=... — 件名・本文は encodeURIComponent でパーセントエンコードする。
  • Wi-Fi: WIFI:T:WPA;S:<SSID>;P:<パスワード>;H:false;; — ここだけ独自のエスケープ規則がある。

tel: と mailto: は素直

電話番号は数字以外を落とすだけ。国番号を使う場合は先頭の + を残す。

1
2
3
4
5
6
7
function telPayload(raw) {
const plus = raw.trim().charAt(0) === '+' ? '+' : '';
const digits = raw.replace(/[^0-9]/g, '');
return 'tel:' + plus + digits;
}
telPayload('03-1234-5678'); // "tel:0312345678"
telPayload('+1 415-555-0100'); // "tel:+14155550100"

メールはクエリ部分だけパーセントエンコードすればよい。

1
2
3
4
5
6
function mailtoPayload(to, subject, body) {
const p = [];
if (subject) p.push('subject=' + encodeURIComponent(subject));
if (body) p.push('body=' + encodeURIComponent(body));
return 'mailto:' + to + (p.length ? '?' + p.join('&') : '');
}

WIFI: は「独自エスケープ」がハマりどころ

Wi-Fi QRの仕様では、SSIDやパスワードに含まれる \ ; , : " の5文字をバックスラッシュでエスケープしなければならない。encodeURIComponent ではなく、この5文字だけを対象にする独自処理が必要だ。ここを忘れると、SSIDにセミコロンや : が入った瞬間にフィールドの区切りと誤認され、読み取り側で接続に失敗する。

1
2
3
4
5
6
7
8
9
10
11
function wifiEscape(s) {
return String(s).replace(/([\;,:"])/g, '\\$1');
}
function wifiPayload({ ssid, pass, enc = 'WPA', hidden = false }) {
const h = hidden ? 'true' : 'false';
if (enc === 'nopass') return `WIFI:T:nopass;S:${wifiEscape(ssid)};H:${h};;`;
return `WIFI:T:${enc};S:${wifiEscape(ssid)};P:${wifiEscape(pass)};H:${h};;`;
}

wifiPayload({ ssid: 'Shop;Guest', pass: 'pa:ss', enc: 'WPA' });
// "WIFI:T:WPA;S:Shop\;Guest;P:pa\:ss;H:false;;"

Shop;Guest;pa:ss: がきちんと \; \: になっている点に注目。末尾の ;; は仕様上のターミネータで、省略しない。

qrcode.js でエンコードする

あとは組み立てた文字列を node-qrcode(ブラウザ版)に渡すだけ。canvasへ描画し、PNG/SVGで書き出せる。

1
2
3
4
5
6
7
8
<script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.1/build/qrcode.min.js"></script>
<canvas id="qr"></canvas>
<script>
const text = wifiPayload({ ssid: 'Shop-Guest', pass: 'guest-pass', enc: 'WPA' });
QRCode.toCanvas(document.getElementById('qr'), text, {
errorCorrectionLevel: 'M', margin: 4, width: 320
});
</script>

誤り訂正レベルは L(約7%)〜H(約30%)。パスワードが長いほどQRは複雑になるので、掲示・印刷用途では誤り訂正を上げすぎず、サイズを大きめにすると読み取りやすい。

まとめ

「読み取ると発信」「読み取るとWi-Fi接続」といった挙動は、埋め込む文字列を正しく組み立てるだけで作れる。tel:mailto: は素直だが、WIFI: は5文字の独自エスケープと末尾 ;; を忘れないことがポイントだ。実際に動く形は 電話番号QR / Wi-Fi QR / メールQR で確認できる(いずれもブラウザ内で完結し、入力は送信しない)。


電話番号・Wi-Fi・メールのQRコードをURIスキームで作る仕組み(tel:/WIFI:/mailto: とqrcode.js)
https://blog.hashito.biz/2026/07/15/tel-wifi-qr-uri-scheme-qrcodejs/
著者
hashito
作成日
2026年7月15日
著作権