Gmail下書きの添付忘れを送信前に発見|GASで件数と容量をdry-run監査
ツールおじ|GoogleアカウントをAIエージェント化
「資料を添付します」と書いたのに、ファイルを付けないまま送信しかけた。反対に、大きな添付が複数入り、送信直前に容量へ気づいた。Gmail下書きが増えるほど、この確認は目視だけでは抜けやすくなります。
この記事では、Gmailの下書きを送信・削除・変更せずに読み取り、本文や件名に「添付」「ファイル」「attachment」があるのに添付数が0件の候補と、容量上限を超える候補だけを集計する無料GASを紹介します。宛先、件名、本文、ファイル名はログへ出しません。
先に知っておきたいこと
- できること: Gmail下書きの添付数、合計容量、添付を示す語と実ファイルの不一致候補をdry-runで確認できます。
- しないこと: メール送信、下書き削除、本文変更、添付追加、Drive保存、ラベル変更は行いません。
- 必要な権限: 初回実行時にGmail下書きの読み取りに必要な権限確認が表示されます。内容に納得できない場合は許可せず停止してください。
- 守る範囲: 最大50件までを既定値にし、実際の宛先・件名・本文・ファイル名をログへ残しません。
- 判定の位置づけ: 「添付が必要か」を確定するものではなく、人が送信前に開いて確認する候補を絞るための監査です。
この方法が向いている場面
- 見積書、申込書、案内資料などをGmail下書きで準備している。
- 定型文に「添付」「ファイル」を含めることが多い。
- 自動送信は避け、最後は人がGmail画面で確認したい。
- 大きな添付が混ざっていないか、送信前に件数だけ先に把握したい。
添付を自動でDriveへ保存する処理や、自動送信をしたい場合のコードではありません。まず読み取り専用の監査を分離しておくと、誤送信や意図しない保存を避けやすくなります。
コピーして使える無料GAS
function auditGmailDraftAttachmentsFree() {
const config = {
dryRun: true,
maxDrafts: 50,
maxTotalAttachmentBytes: 8 * 1024 * 1024,
attachmentWords: /添付|ファイル|attachment/i,
maxIssueRowsInLog: 20
};
validateAttachmentAuditConfig_(config);
// 安全装置: この無料コードは読み取り専用のdry-runだけを許可します。
if (config.dryRun !== true) {
throw new Error('dryRun は true のまま実行してください。');
}
const allDrafts = GmailApp.getDrafts();
const targetDrafts = allDrafts.slice(0, config.maxDrafts);
const issues = [];
let attachmentCount = 0;
let attachmentBytes = 0;
let keywordWithoutAttachmentCount = 0;
let overSizeCount = 0;
targetDrafts.forEach(function(draft, index) {
const message = draft.getMessage();
const subject = String(message.getSubject() || '');
const plainBody = String(message.getPlainBody() || '');
const attachments = message.getAttachments({
includeInlineImages: false,
includeAttachments: true
});
const totalBytes = attachments.reduce(function(sum, attachment) {
const size = Number(attachment.getSize() || 0);
return sum + (Number.isFinite(size) ? size : 0);
}, 0);
const mentionsAttachment =
config.attachmentWords.test(subject + '\n' + plainBody);
const flags = [];
if (mentionsAttachment && attachments.length === 0) {
flags.push('ATTACHMENT_WORD_WITHOUT_FILE');
keywordWithoutAttachmentCount += 1;
}
if (totalBytes > config.maxTotalAttachmentBytes) {
flags.push('TOTAL_ATTACHMENT_SIZE_OVER_LIMIT');
overSizeCount += 1;
}
if (attachments.some(function(attachment) {
return Number(attachment.getSize() || 0) === 0;
})) {
flags.push('ZERO_BYTE_ATTACHMENT');
}
attachmentCount += attachments.length;
attachmentBytes += totalBytes;
if (flags.length > 0) {
issues.push({
draftNo: index + 1,
flags: flags,
attachmentCount: attachments.length,
totalMiB: roundMiB_(totalBytes)
});
}
});
const summary = {
dryRun: true,
availableDrafts: allDrafts.length,
checkedDrafts: targetDrafts.length,
truncated: allDrafts.length > targetDrafts.length,
attachmentCount: attachmentCount,
totalAttachmentMiB: roundMiB_(attachmentBytes),
keywordWithoutAttachmentCount: keywordWithoutAttachmentCount,
overSizeCount: overSizeCount,
issueCount: issues.length,
issues: issues.slice(0, config.maxIssueRowsInLog)
};
// 宛先・件名・本文・ファイル名は出力しません。
console.log(JSON.stringify(summary));
return summary;
}
function validateAttachmentAuditConfig_(config) {
if (!config || typeof config !== 'object') {
throw new Error('設定が見つかりません。');
}
if (config.dryRun !== true) {
throw new Error('dryRun=false はこの無料コードでは利用できません。');
}
if (!Number.isInteger(config.maxDrafts) ||
config.maxDrafts < 1 ||
config.maxDrafts > 100) {
throw new Error('maxDrafts は1〜100の整数にしてください。');
}
if (!Number.isFinite(config.maxTotalAttachmentBytes) ||
config.maxTotalAttachmentBytes < 1024 * 1024 ||
config.maxTotalAttachmentBytes > 20 * 1024 * 1024) {
throw new Error('容量上限は1MiB〜20MiBの範囲にしてください。');
}
if (!Number.isInteger(config.maxIssueRowsInLog) ||
config.maxIssueRowsInLog < 1 ||
config.maxIssueRowsInLog > 50) {
throw new Error('maxIssueRowsInLog は1〜50の整数にしてください。');
}
if (!(config.attachmentWords instanceof RegExp)) {
throw new Error('attachmentWords は正規表現で指定してください。');
}
}
function roundMiB_(bytes) {
return Math.round((bytes / 1024 / 1024) * 100) / 100;
}実行手順
- Googleスプレッドシートを新規作成し、「拡張機能」からApps Scriptを開きます。
- 上のコードを貼り付けて保存します。
- 最初はテスト用のGmail下書きを2件だけ用意します。1件は「資料を添付します」と書いて添付なし、もう1件は小さなテストファイルを付けます。
- `auditGmailDraftAttachmentsFree` を選び、実行します。
- 権限確認を読み、対象アカウントがテスト用であることを確認してから許可します。
- Apps Scriptの「実行ログ」で、`checkedDrafts`、`issueCount`、`flags`を確認します。
- `draftNo`は監査時の並び順です。候補が出たらGmailの下書きを人が開き、添付の要否と容量を確認します。
最初から業務用下書き全件へ使わず、テスト下書きで「添付語あり・添付なし」と「添付あり」の両方を確認してください。
ログの読み方
- `ATTACHMENT_WORD_WITHOUT_FILE`: 件名または本文に添付を示す語がある一方、通常添付が0件です。
- `TOTAL_ATTACHMENT_SIZE_OVER_LIMIT`: その下書きの添付合計が設定値を超えています。
- `ZERO_BYTE_ATTACHMENT`: サイズ0として取得された添付があります。取得仕様やファイル状態を人が確認してください。
- `truncated: true`: 下書き総数が`maxDrafts`を超え、今回は先頭の一部だけを確認しています。
ログには本文やファイル名を出していません。候補の内容確認はGmail画面で行い、機密情報や個人情報をApps Scriptのログへ複製しない運用にしてください。
失敗しやすい点と制限
- Gmailの署名内に「添付ファイル」という定型文があると、確認不要な候補が増える場合があります。正規表現の語を自分の運用に合わせて狭めてください。
- Google Driveの共有リンクはGmailの添付ファイルとして数えません。リンク送付を確認したい場合は、別のURL監査として設計してください。
- インライン画像は既定で除外しています。署名画像を通常添付として数えないためです。
- Apps ScriptやGmailには利用上限があります。大量の下書きがある場合も`maxDrafts`を一度に増やさず、少量で確認してください。
- 下書きの取得順は運用中に変わることがあります。`draftNo`を恒久IDとして保存しないでください。
- 添付の内容、安全性、法令・契約上の送付可否は判定しません。送信前の最終判断は利用者が行ってください。
- このコードは下書きを送信、削除、変更しません。自動送信や自動削除へ改変する場合は、別のレビューと停止手順が必要です。
公開前チェックリスト
- [ ] `dryRun: true`のままになっている。
- [ ] テスト用下書きで期待する2パターンを確認した。
- [ ] `maxDrafts`を必要以上に増やしていない。
- [ ] 宛先、件名、本文、ファイル名をログへ追加していない。
- [ ] 候補をGmail画面で人が確認してから送信する。
- [ ] 添付の内容や送付可否を自動判定だと思い込まない。
まとめ
添付忘れ対策で最初に自動化したいのは、送信そのものではなく「確認候補を安全に絞ること」です。この無料GASは、下書きを変更せず、添付を示す語と添付数、合計容量だけをdry-run監査します。
定型連絡を複数テンプレートから作り、送信前の人間確認を残したい場合は、次の有料Tipsが関連します。
Gmail下書きテンプレGAS Proを見る

GasおじのTips商品一覧を見る

※本記事は学習・検証用の例です。実データへ適用する前に、テスト用下書きと少量のデータで確認してください。Google公式・Google公認の商品ではありません。Google側の仕様、権限、利用上限、アカウント設定により動作条件が変わる場合があります。
