送信待ちで止まったメールを追う(sys_email)
ServiceNow で「通知メールが届かない」「自動メールが本当に送られたのか分からない」というとき、最終的に確認するのが メールの実レコードそのものです。ServiceNow では、実際に送受信された(あるいは送ろうとした)メール1通が、そのまま1レコードとして sys_email(画面ラベルは Email) に残ります。送信待ちのメールも、送れたメールも、受信したメールも、すべて同じこのテーブルに溜まります。
この記事は、ServiceNow の通知設定は触ったことがあるが、「実際に作られたメールがどこに、どんな状態で残るのか」をこれから確認したい管理者・開発者を想定しています。PDI(Zurich / OOTB)で sys_email を実際に開き、1通=1レコードであることを確認します。処理種別を表す type、置き場を表す mailbox、処理状態を表す state を、実機の件数とあわせて見ていきます。「通知が飛ばない」調査では、どこを見れば「メールが生成されたのか」「送信で止まっているのか」を切り分けられるかが起点になります。
なお、この記事は通知が飛ぶまでの流れ(Email Notification)とは役割が違います。あちらが扱うのは sysevent_email_action という「通知の定義(設計図)」です。本記事が扱うのは、その定義から生成された個々のメールの実体 sys_email です。定義を見るのか、実体を見るのかで、調べるテーブルが変わります。
この記事で分かること
メールの実体が sys_email(Email)の1通=1レコードとして、送受信を問わず1つのテーブルに溜まること
処理種別 type(send-ready / sent / send-failed / send-ignored / received など7種)の意味
置き場 mailbox(Outbox / Sent / Inbox / Junk / Failed など)と type の対応
PDI 実機では 767 件すべてが send-ready/Outbox に溜まっていて、送信されずに止まっていること
sys_email が append-only ではなく、状態遷移のたびに同じ行が更新されること(syslog との違い)
「通知が飛ばない」を 定義(sysevent_email_action)の問題か、送信側の問題かで切り分ける見方
この記事の内容は ServiceNow の PDI(Personal Developer Instance)Zurich(ズーリッヒ)リリースの OOTB(初期設定)で確認した個人メモです。本番環境やカスタマイズ済み環境では、メールの件数・type / mailbox の分布が異なります。送信スケジューラや SMTP の実挙動には踏み込みません。
sys_email(メールの実レコード)とは
sys_email は、ServiceNow で実際に送受信された/されようとしたメール1通を、そのまま1レコードとして記録するテーブルです。通知定義が「このメールを送る」と判定すると、その都度 sys_email に1行が作られます。受信メールも同じテーブルに入ります。つまり sys_email は、送信キュー・送信済みログ・受信箱を兼ねた、メールの実体置き場です。
下の画面は、PDI(Zurich / OOTB)の sys_email を type でグループ化したものです。本来なら send-ready(送信待ち)・sent(送信済み)・received(受信)などに分かれるはずですが、この PDI では1種類に偏っていました。

これは通知定義(sysevent_email_action)とは別物です。通知定義は「いつ・誰に・何を送るか」を決めた設計図で、sys_email はそこから生まれた1通1通の実体です。設計図が1つでも、条件に合致するたびに sys_email の行は増えていきます。
メールが流れる道筋(type と mailbox の遷移)
メール1通は、生成から送信(または受信)まで状態を変えながら進みます。今回の PDI(Zurich / OOTB)で確認した type / mailbox の関係を図にすると次のとおりです。

送信側 … 通知が「送る」と判定すると、type=send-ready / state=ready / mailbox=Outbox で1行生成されます。そこから3パターンに分かれます。
成功:type=sent / mailbox=Sent
失敗:type=send-failed / mailbox=Failed(error_string にエラー)
対象外:type=send-ignored / mailbox=Skipped
受信側 … 外部から受信したメールは type=received / mailbox=Inbox で1行作られます。中身は受信メールアクション(Inbound Email Action)が処理します。迷惑メール扱いは received-ignored / Junk です。
この PDI では、767 件すべてが send-ready のまま Outbox に溜まっていました。PDI に有効なメール送信(SMTP)が設定されていないためで、メールは生成されるものの Sent へ一切進みません。「PDI で通知の動きは確認できるのに、実際にメールが届かない」のはこれが理由です。

sys_email はどんなテーブルか
名前のとおりシステム系ですが、継承元を確認するとシンプルでした。今回の PDI(Zurich / OOTB)では、sys_email の super_class(継承元)は空で、task も cmdb も継承しない 独立したルート基底テーブルです。メールの実体を専門に受け止める器として、業務テーブルとは独立しています(固有フィールドは33)。
1通のメールが持つ主なフィールドは次のとおりです。

中心になるのは type(処理種別)・state(処理状態)・mailbox(置き場) の3つです。これらが今のメールの状況を表します。それ以外のフィールドは、宛先・中身・由来・送受信メタに整理できます。

宛先 … recipients / direct(To)、copied(Cc)、blind_copied(Bcc)、reply_to。
中身 … subject(件名)、body / body_text(本文)、content_type、importance。
由来 … target_table + instance で、どのレコードから生成されたメールかを指します。例えば On-Call の通知なら target_table=cmn_rota といった具合です。
送受信メタ … notification_type(既定 SMTP)、message_id、headers、送信失敗時の error_string。
ここで1つ大事な違いがあります。システムログ syslog は追記専用(append-only)で、一度書いたら更新しません。一方 sys_email は sys_updated_on / sys_mod_count を持ち、send-ready → sent のように状態が進むたびに同じ行が更新されます。メールは「動く」レコードなのです。フィールド定義は次のURLで確認できます(先頭の <YourInstance> は自分のインスタンスに置き換えてください)。
https://<YourInstance>/sys_dictionary_list.do?sysparm_query=name=sys_email^elementISNOTEMPTY
type:メールの処理種別
type は、そのメールが「送信待ちなのか・送れたのか・受信なのか」を表す処理種別です。PDI では選択肢が7種類ありました。それぞれの意味と、進む先の mailbox、そして実機の件数を示します。

実機で type の選択肢を開くと、内部値と表示名の対応が確認できます。

繰り返しになりますが、今回の PDI では send-ready が767件で全体を占め、sent・send-failed・received はいずれも0件でした。これは「メールは生成されているが、送信処理が走っていない(PDI に送信設定が無い)」状態を意味します。だから障害調査では、まず type で絞るのが定石です。send-ready ばかりなら送信側、send-failed があれば error_string、行が無ければそもそも生成されていない(=通知定義側)、と切り分けられます。
https://<YourInstance>/sys_email_list.do?sysparm_query=GROUPBYtypemailbox:メールがどこに置かれているか
mailbox は、メールがどの箱に入っているかを表します。sys_mailbox(Mailbox) を参照します。PDI には Outbox / Sent / Inbox / Junk / Failed / Received / Skipped の7つ が定義されていました。type とほぼ連動していて、送信前は Outbox・送信済みは Sent・失敗は Failed・受信は Inbox に置かれます。

ここでも実機の事実は明快で、767件すべてが Outboxでした。Sent も Inbox も0件です。送信されないメールが Outbox に溜まり続けている、という PDI の状況がそのまま見えます。content_type は text/html が320件、multipart/mixed が278件、text/plain が169件でした。重要度 importance=high のメールも112件あります。集計値は次のとおりです。

https://<YourInstance>/sys_email_list.do?sysparm_query=GROUPBYmailbox「通知が飛ばない」を sys_email で切り分ける
読者の一番の疑問は「通知メールが飛ばないとき、どこを見ればいいか」です。ここで効くのが、定義と実体を分けて見るという発想です。

sys_email に行が無い … メールがそもそも生成されていません。問題は通知定義(sysevent_email_action)側です。通知が active か、条件・宛先が合っているか、いつ送るか(Send when)を確認します。宛先の組み立てが疑わしいなら通知デバイス(cmn_notif_device)も確認します。
行はあるが type=send-ready / mailbox=Outbox のまま … 生成はされたが送信されていません。送信側(メールアカウント・SMTP の有効化)の問題です。PDI ではこれが既定状態です。
type=send-failed … 送信を試みて失敗しています。error_string にエラーが入ります。
type=send-ignored / mailbox=Skipped … 送信対象外として無視されています。
つまり、「定義(sysevent_email_action)を見るのか、実体(sys_email)を見るのか」を切り替えるのがコツです。sys_email に行があるかどうかが、定義側と送信側の分かれ目になります。中身(件名・本文・テンプレート)の作りは、メールテンプレートとレイアウトが参考になります。
実機で確認するときに見るべきURL
最後に、今回見た画面を自分のインスタンスで開くためのURLをまとめます(<YourInstance> は置き換えてください)。
# メールを処理種別でグループ化
https://<YourInstance>/sys_email_list.do?sysparm_query=GROUPBYtype
# メールを置き場でグループ化
https://<YourInstance>/sys_email_list.do?sysparm_query=GROUPBYmailbox
# 送信待ち(Outbox)のメールを新しい順に
https://<YourInstance>/sys_email_list.do?sysparm_query=mailbox=outbox^ORDERBYDESCsys_created_on
# sys_email のフィールド定義
https://<YourInstance>/sys_dictionary_list.do?sysparm_query=name=sys_email^elementISNOTEMPTY
まとめ
メールの実体は sys_email(Email)の1通=1レコードとして、送受信を問わず1つのテーブルに溜まる。PDI では767件。
sys_email は独立したルート基底テーブルだが、append-only ではなく、状態遷移のたびに同じ行が更新される(syslog との違い)。中心は type / state / mailbox。
type は処理種別で、PDI 実機では send-ready が767件(全件)、sent・send-failed・received は0件。送信設定が無いため Outbox に溜まったまま。
mailbox は置き場で、type と連動。PDI は全件 Outbox。content_type は text/html 320 / multipart/mixed 278 / text/plain 169。
「通知が飛ばない」は 定義(sysevent_email_action)か送信側かで切り分ける。sys_email に行があるかどうかが分かれ目。
sys_email が分かると、関連する記事が「定義する → メールが生成される → 送受信される」という流れでつながって見えてきます。
メールの障害調査でログ全体を追いたいときは、システムログ syslogも合わせてどうぞ。