What It Is
An Inbound Email Action is a server-side processing rule that executes JavaScript when ServiceNow receives an email matching specific criteria. The system evaluates incoming emails against conditions you define (sender address, subject line patterns, target mailbox) and runs custom scripts to create records, update existing data, or trigger workflows. This eliminates the manual step of reading emails and translating their content into ServiceNow records, which is critical for organizations processing hundreds of emails daily from customers, vendors, or monitoring systems.
Architecturally, Inbound Email Actions live in the System Mailboxes application within ServiceNow's integration layer. They execute after the email parsing engine extracts headers and body content but before any record creation occurs. The actions are stored in the sys_email_action table and are evaluated in order priority during the email processing pipeline. Each action has access to the parsed email object through the email and email_message variables within its script execution context.
The underlying execution environment connects directly to ServiceNow's email processing daemon, which polls configured mailboxes and processes messages in near real-time. When an email arrives, the system creates a sys_email record containing the raw message data, then evaluates each active Inbound Email Action against the message. Actions that match execute their scripts with full database access through GlideRecord APIs, making them functionally equivalent to Business Rules but triggered by external email events rather than internal record changes.
You cannot function without Inbound Email Actions when your organization needs automated email-to-record conversion at scale. Customer support teams sending incident reports via email, monitoring systems sending alert notifications, or vendors submitting service requests through email all require this automation to maintain reasonable response times. Manual processing becomes impossible when you're receiving 50+ actionable emails per day, and email forwarding to users defeats the purpose of centralizing work in ServiceNow. The business necessity becomes critical when email processing delays directly impact SLA compliance or when manual email handling creates audit trail gaps that regulatory requirements cannot tolerate.
Platform administrators own the configuration and maintenance of Inbound Email Actions, though the actual script development often requires developer-level JavaScript skills. The admin configures mailbox connections, sets up condition matching, and manages the action priority order, while developers write the record creation and data parsing logic within the action scripts. In mature implementations, a platform owner typically defines the email processing strategy and mailbox architecture, while delegating individual action configuration to application-specific admins who understand the target table structures and business rules.
Recent ServiceNow releases have improved email processing reliability and added better debugging capabilities through enhanced logging in the System Logs > Email module. Vancouver and later versions include better attachment handling and support for larger email volumes, while Xanadu introduced improved script execution monitoring that helps identify performance bottlenecks in complex email processing workflows. The core functionality remains unchanged, but error visibility and troubleshooting capabilities have significantly improved for administrators managing high-volume email integration scenarios.
Where to Find and Configure It
Navigate to System Mailboxes > Administration > Inbound Actions to create and manage email actions. This is where you define the matching conditions, set execution order, and write the processing scripts. Access System Mailboxes > Administration > Mailboxes to configure the actual email accounts that ServiceNow polls for incoming messages. Check System Mailboxes > Emails to see the raw email records and verify which actions processed each message.
In Studio or App Engine Studio, search for sys_email_action to view actions within your application scope. Monitor execution results at System Logs > Email to troubleshoot processing issues and verify successful record creation. Review processed emails and their target records through System Mailboxes > Processing > Email Processing for detailed execution tracking.
Scoped applications can only access Inbound Email Actions created within their scope. Global actions are visible to all applications but should be avoided for application-specific email processing to maintain proper separation of concerns.
How It Works Step by Step
ServiceNow's email processing daemon continuously polls configured mailboxes based on their polling frequency settings, typically every 5-10 minutes for production systems. When new emails arrive, the system downloads the complete message including headers, body content, and attachments, then creates a sys_email record containing the parsed message data. This record includes normalized sender information, cleaned subject lines, and structured body content that Inbound Email Actions can access through predefined script variables.
The system evaluates each active Inbound Email Action against the incoming message in order of their Order field value, starting with the lowest number. For each action, ServiceNow checks the condition fields (From, Subject contains, Mailbox) against the email data. If all conditions match, the action executes its script with full database access, and if the Stop processing flag is set, no additional actions evaluate against this email.
During script execution, actions have access to the email object containing parsed message data and the email_message object with raw content. The script typically creates or updates records using GlideRecord operations, processes attachments, and sets the email's state field to prevent reprocessing. Successful execution logs details to System Logs > Email, while errors trigger email notifications to administrators and mark the email for manual review.
Enjoying this? Get one deep-dive per week.
Join 1,000+ ServiceNow pros — scripts, GlideRecord patterns, Flow Designer techniques, and career moves. Free.
The Execution Order
- Email daemon polls configured mailbox and downloads new messages
- System creates
sys_emailrecord with parsed headers, body, and attachment references - Query active Inbound Email Actions ordered by
Orderfield (ascending) - Evaluate condition fields against email data (sender, subject, mailbox, custom conditions)
- Execute matching action's script with
emailandemail_messagevariables available - Update email state to
processedorerrorand log execution results - Stop processing if
Stop processingflag is checked, otherwise continue to next action
// Parse email content and create incident
var senderEmail = email.getHeader('From');
var subjectLine = email.getHeader('Subject');
var description = email.getMessage().toString();
// Extract priority from subject line
var priority = '3'; // default
if (subjectLine.indexOf('[URGENT]') > -1) {
priority = '1';
} else if (subjectLine.indexOf('[HIGH]') > -1) {
priority = '2';
}
// Create new incident
var inc = new GlideRecord('incident');
inc.initialize();
inc.caller_id = senderEmail;
inc.short_description = subjectLine;
inc.description = description;
inc.priority = priority;
inc.state = '1'; // New
var incidentSysId = inc.insert();
// Update email record with target
email.setValue('target_table', 'incident');
email.setValue('target_sys_id', incidentSysId);Real-World Scenarios
Customer Support Incident Creation from Help Desk Email
Your organization receives 200+ customer emails daily at support@company.com and needs automatic incident creation with proper categorization based on email content. Manual processing creates 2-hour delays and inconsistent ticket quality that violates SLA commitments to enterprise customers.
// Configuration:
// From: * (any sender)
// Subject contains: [CASE] OR support@ in mailbox
// Mailbox: support@company.com
// Order: 100
var customerEmail = email.getHeader('From');
var subject = email.getHeader('Subject');
var body = email.getMessage().toString();
// Find or create customer record
var customer = new GlideRecord('sys_user');
customer.addQuery('email', customerEmail);
customer.query();
if (!customer.next()) {
// Create contact for external customers
customer.initialize();
customer.email = customerEmail;
customer.first_name = 'External';
customer.last_name = 'Customer';
customer.active = false;
customer.insert();
}
// Determine category from subject keywords
var category = 'inquiry';
var urgency = '3';
if (subject.toLowerCase().indexOf('password') > -1) {
category = 'password';
urgency = '2';
} else if (subject.toLowerCase().indexOf('access') > -1) {
category = 'access';
urgency = '2';
}
// Create incident with parsed data
var inc = new GlideRecord('incident');
inc.initialize();
inc.caller_id = customer.getUniqueValue();
inc.short_description = subject.substring(0, 160);
inc.description = 'Email from: ' + customerEmail + '\n\n' + body;
inc.category = category;
inc.urgency = urgency;
inc.assignment_group = '287ebd7da9fe198100f92cc8d1d2154e'; // IT Help Desk
var sysId = inc.insert();
// Link email to incident
email.setValue('target_table', 'incident');
email.setValue('target_sys_id', sysId);Watch for duplicate incident creation when customers reply to existing tickets - implement subject line parsing to match incident numbers and update existing records instead. The assignment group reference must be valid or the incident will default to unassigned, breaking your routing workflow. Test with various email clients since HTML formatting and encoding can break body text parsing logic.
Monitoring System Alert Processing with Severity Mapping
Network monitoring tools send alerts to alerts@company.com with structured subject lines containing severity levels and device information. These must become ServiceNow events or incidents based on severity, with automatic assignment to appropriate technical teams.
// Configuration:
// From: monitoring@company.com
// Subject contains: [ALERT]
// Mailbox: alerts@company.com
// Order: 50
// Stop processing: true
var subject = email.getHeader('Subject');
var alertBody = email.getMessage().toString();
// Parse structured subject: [ALERT][CRITICAL] Server01 - Disk Space
var severityMatch = subject.match(/\[ALERT\]\[([A-Z]+)\]/);
var severity = severityMatch ? severityMatch[1] : 'INFO';
// Extract device name and alert type
var deviceMatch = subject.match(/\]\s([A-Za-z0-9-]+)\s-\s(.+)$/);
var deviceName = deviceMatch ? deviceMatch[1] : 'Unknown';
var alertType = deviceMatch ? deviceMatch[2] : subject;
// Create incident for CRITICAL/HIGH, event for others
if (severity === 'CRITICAL' || severity === 'HIGH') {
var inc = new GlideRecord('incident');
inc.initialize();
inc.short_description = alertType + ' - ' + deviceName;
inc.description = alertBody;
inc.urgency = (severity === 'CRITICAL') ? '1' : '2';
inc.impact = (severity === 'CRITICAL') ? '1' : '2';
inc.assignment_group = '287ebd7da9fe198100f92cc8d1d2154f'; // Network Team
inc.category = 'network';
inc.state = '2'; // In Progress for critical alerts
inc.insert();
} else {
// Create event for INFO/WARNING alerts
var evt = new GlideRecord('em_event');
evt.initialize();
evt.source = 'Email Monitor';
evt.node = deviceName;
evt.description = alertType;
evt.severity = (severity === 'WARNING') ? '3' : '5';
evt.insert();
}Monitor for email storms from failing systems that could create hundreds of duplicate incidents. Implement deduplication logic based on device name and alert type, and set rate limiting in your monitoring tools to prevent overwhelming ServiceNow.
Vendor Change Request Submission with Approval Routing
External vendors submit change requests via email to changes@company.com using a standardized template with specific fields in the message body. These need automatic change record creation with proper approval workflows and vendor contact tracking.
// Configuration:
// From: *@vendor1.com OR *@vendor2.com
// Subject contains: [CHANGE REQUEST]
// Mailbox: changes@company.com
var senderEmail = email.getHeader('From');
var body = email.getMessage().toString();
var subject = email.getHeader('Subject');
// Parse structured email body for required fields
var scheduledDateMatch = body.match(/Scheduled Date:\s*([\d\/\-\s:]+)/i);
var impactMatch = body.match(/Impact:\s*([^\n]+)/i);
var descriptionMatch = body.match(/Description:\s*([\s\S]+?)(?=\n[A-Z][a-z]+:|$)/i);
// Validate required fields
if (!scheduledDateMatch || !impactMatch || !descriptionMatch) {
gs.addErrorMessage('Incomplete change request from ' + senderEmail);
email.setValue('state', 'error');
return;
}
// Create change request
var cr = new GlideRecord('change_request');
cr.initialize();
cr.short_description = subject.replace('[CHANGE REQUEST]', '').trim();
cr.description = descriptionMatch[1].trim();
cr.requested_by = 'vendor.contact@company.com'; // Generic vendor contact
cr.start_date = new GlideDateTime(scheduledDateMatch[1]);
cr.impact = (impactMatch[1].toLowerCase().indexOf('high') > -1) ? '2' : '3';
cr.risk = '3'; // Medium risk for vendor changes
cr.type = 'standard';
cr.state = '-5'; // Pending approval
cr.assignment_group = '287ebd7da9fe198100f92cc8d1d2154e'; // Change Management
// Add vendor email as additional comments
cr.comments = 'Submitted via email from: ' + senderEmail + '\n\nOriginal message:\n' + body;
var changeSysId = cr.insert();
// Update email tracking
email.setValue('target_table', 'change_request');
email.setValue('target_sys_id', changeSysId);Regular expression parsing breaks when vendors modify their email templates or add unexpected formatting, so implement validation logging to catch parsing failures early. The requested_by field must reference a valid user record or change approvals will fail to route properly. Consider implementing email auto-reply functionality to confirm receipt and provide the change request number to vendors for tracking purposes.
The Classic Mistake
Processing emails without checking for duplicate email message IDs causes infinite loops when email replies trigger additional outbound emails.
// This will create infinite email loops
var incident = new GlideRecord('incident');
incident.initialize();
incident.short_description = email.subject;
incident.description = email.body_text;
incident.caller_id = email.from;
incident.state = '1';
var incidentId = incident.insert();
// Send confirmation email - this triggers another inbound email!
var notification = new GlideRecord('sysevent_email_action');
notification.initialize();
notification.event = 'incident.inserted';
notification.instance = incidentId;
notification.insert();
// No check if this email was already processedThis creates dozens or hundreds of duplicate records because email servers often deliver the same message multiple times, and reply notifications trigger new inbound emails. ServiceNow processes each message independently without built-in deduplication, so the same email creates multiple incidents. Users see duplicate tickets flooding the system, but admins don't realize the sys_email table contains the same message_id multiple times until they check the email processing logs.
// Check if this email was already processed
var existingEmail = new GlideRecord('sys_email');
existingEmail.addQuery('message_id', email.message_id);
existingEmail.addQuery('sys_created_on', '>=', gs.daysAgoStart(7));
existingEmail.query();
if (existingEmail.getRowCount() > 1) {
gs.log('Duplicate email detected: ' + email.message_id, 'InboundEmailAction');
return;
}
// Also check for existing records by subject/sender
var existingIncident = new GlideRecord('incident');
existingIncident.addQuery('short_description', 'CONTAINS', email.subject.substring(0, 50));
existingIncident.addQuery('caller_id', email.from);
existingIncident.addQuery('sys_created_on', '>=', gs.daysAgoStart(1));
existingIncident.query();
if (existingIncident.next()) {
// Update existing instead of creating new
var journal = new GlideRecord('sys_journal_field');
journal.initialize();
journal.element = 'work_notes';
journal.element_id = existingIncident.sys_id;
journal.value = 'Email reply: ' + email.body_text;
journal.insert();
return;
}Always check email.message_id against the sys_email table and search for similar existing records before creating anything new.
When to Use This vs Alternatives
Inbound Email Actions are the right choice when you need to create or update ServiceNow records based on incoming emails with complex business logic. Use this when standard email-to-table functionality in System Mailboxes > Email Properties is too limited, or when you need to parse email content, validate data, or perform multi-table operations.
When Inbound Email Actions Are Correct
Choose Inbound Email Actions when you need conditional logic, email parsing, or multi-step processing that system mailboxes can't handle. They excel at ticket routing based on email content, customer lookup by domain, or creating child records alongside the main record. Email-to-table functionality only does simple field mapping without scripting capability.
When to Use System Mailboxes Instead
Use System Mailboxes > Email Properties for simple email-to-record creation with direct field mapping and no custom logic. This approach is faster to configure and more reliable for basic scenarios like contact form submissions or survey responses. It also handles large email volumes better because there's no script execution overhead.
When You Need Both Together
Combine Inbound Email Actions with Transform Maps when processing structured email data that needs complex validation and formatting. Use email actions for initial processing and duplicate detection, then call transform maps for the actual record creation. This separation keeps business logic in email actions while leveraging transform map field mapping capabilities and error handling.
Platform Interactions & Side Effects
- Email processing creates records in
sys_emailtable with full email headers, body content, and processing status - Business Rules on target tables fire normally, but the
current.operation()returns 'insert' even for email-triggered updates - ACL evaluation uses the email processing user context (typically
system), not the email sender's user account - Update Sets capture inbound email action modifications but not the email processing results or created records
- Script execution runs in background processing thread with 60-second timeout limit and no user session context
- Failed email processing moves messages to
sys_email_errortable with error details and stack traces - Notification events triggered by email processing can create feedback loops if they send emails back to monitored addresses
- Attachments are automatically created as
sys_attachmentrecords linked to the email record, accessible viaemail.attachments - Transform Maps called from email actions inherit the email processing transaction but create separate audit trail entries
- Memory usage increases with large emails or attachments since entire email content loads into script scope during processing
Debugging and Troubleshooting
Email processing failures typically manifest as emails disappearing without creating expected records, or records being created with incorrect or missing data. Users report that emails sent to monitored addresses don't generate tickets, while admins see successful email retrieval in System Mailboxes > POP3/IMAP Accounts but no corresponding records in target tables. The most common symptoms include emails stuck in Received state without processing, or partial record creation where only some fields populate correctly.
Start debugging by checking System Log > All for script errors and email processing messages, then examine the sys_email table to verify emails are being received and matched to the correct inbound action. Enable email debugging by setting glide.email.log.level to debug and glide.email.debug to true to capture detailed processing information.
Look for specific error patterns like "ReferenceError: email is not defined" indicating script scope issues, "Script execution time exceeded" for timeout problems, or "No matching inbound action found" for condition failures. The sys_email_error table contains detailed error messages and stack traces for failed processing attempts. Check the Processing Status field on email records to identify where processing failed.
Diagnostic Checklist:
- Verify the inbound email action
Activecheckbox is enabled andOrderfield places it before competing rules - Test condition logic by querying
sys_emailwith the same criteria used inConditionfield - Check mailbox configuration in
System Mailboxesmatches emailMailboxfield in inbound action - Add
gs.log()statements at script beginning and end to confirm execution flow - Validate email object properties by logging
email.subject,email.from, andemail.body_textvalues - Review recent
sys_email_errorrecords for script exceptions and processing failures - Test with simple email action that only logs received emails before implementing complex business logic
Quick Reference
- Email processing order is determined by
Orderfield value (lowest processes first), not creation date or alphabetical sorting - Script timeout limit is 60 seconds total execution time, after which email moves to
sys_email_errortable - Maximum email attachment size is 1024MB by default, controlled by
com.glide.attachment.max_sizeproperty - Email body content is available as both
email.body_text(plain text) andemail.body(HTML format) - Failed emails retry 3 times with exponential backoff (1 min, 5 min, 15 min) before moving to error table
- Email headers are accessible via
email.headersobject, including custom X-headers for routing logic - Condition field supports dot-walking but not complex expressions - use script for advanced logic instead
- Email processing stops at first matching active inbound action - subsequent rules don't execute
- Watermark functionality preserves last processed email ID to prevent reprocessing during mailbox polling
- System property
glide.email.processing.asynccontrols whether emails process immediately or queue for background processing