Ask for Approval Activity does not take string value for user email.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
Hi Experts,
I’m working on a use case where a user enters an email address in a catalog item form. This email can be personal or official, and it may not exist in the system (i.e., no corresponding record in the sys_user table).
My goal is to send an acknowledgement notification to this entered email, asking the recipient to approve or reject based on certain terms and conditions.
I’ve built a flow using the Ask for Approval action. However, based on my research and testing, this action only accepts reference values (like a sys_user record), and not a plain string or email variable. Since the entered email might not belong to a user in the system, this approach doesn’t work for my scenario.
I’m aware that I could use the Send Email action, but that would make the workflow more complex. It also wouldn’t allow me to track the approval in the approval tables, which I need for follow-up actions and reporting.
Has anyone come across a similar use case where the Ask for Approval activity can be used with a string variable (email) instead of a reference? Or is there a recommended workaround that still allows tracking in the approval tables?
Thanks in advance!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
ServiceNow – Approvals to External Email (No sys_user) with Tracking in Approval Tables
Use Case
A catalog item asks for an arbitrary email. That email may not exist as sys_user. You want to send an acknowledgement + approve/reject and track the decision in sysapproval_approver.
Constraint
Ask for Approval requires a sys_user reference (or group/role). It cannot take a raw email string. Email approvals also require a known user.
Recommended Pattern
1) Create or find a lightweight sys_user for that email (idempotent).
2) Use Ask for Approval referencing that sys_user, so tracking lands in sysapproval_approver.
3) Email the approver with secure one-click links (token) to approve/reject via Scripted REST.
4) Optionally deactivate/archive the external user later.
Subflow: GetOrCreateExternalApproverByEmail
Inputs: email
Outputs: approver_user_sys_id
Script Step:
(function execute(inputs, outputs) {
var email = (inputs.email + '').trim().toLowerCase();
if (!email) { outputs.approver_user_sys_id = ''; return; }
var user = new GlideRecord('sys_user');
user.addQuery('email', email);
user.setLimit(1);
user.query();
if (user.next()) { outputs.approver_user_sys_id = user.getUniqueValue(); return; }
var ext = new GlideRecord('sys_user');
ext.initialize();
ext.user_name = email;
ext.email = email;
ext.name = email;
ext.active = true;
ext.web_service_access_only = true;
var extId = ext.insert();
outputs.approver_user_sys_id = extId;
})(inputs, outputs);
Main Flow
- Trigger: RITM created
- Subflow: GetOrCreateExternalApproverByEmail (email = vars.external_email)
- Ask for Approval → Approvers = outputs.approver_user_sys_id
- Send Email → include Approve/Reject links with token
Tokenized One-Click (Scripted REST)
- Table u_approval_token: approval_sys_id, token, action, expires_on, used
- Approve URL: /api/x_app/approval/oneclick?token=XYZ&action=approve
- Server logic:
• Validate token + expiry
• Load sysapproval_approver by token.approval_sys_id
• If state=requested → set state=approved or rejected; set comments; mark token used
• Return friendly HTML
Benefits
- Native tracking/reporting in sysapproval_approver
- Works for any email (no pre-provisioned user)
- External user never needs to log in (web_service_access_only + tokens)
Notes & Risks
- Identity assurance: token design with short expiry and one-time use
- Avoid including ticket data in the email
- Optionally add the user to an “External Approvers” group for visibility
- Clean up: set active=false after decision (optional)
TL;DR
Ask for Approval needs sys_user. Create/lookup a lightweight user by email; send tokenized approval links; update sysapproval_approver via Scripted REST. You get simple UX + full OOB tracking.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
ServiceNow – Handling Approvals for Emails Not in sys_user (External Approvals)
Issue:
A user enters an email address in a catalog item. The email may be personal or not in sys_user. The goal is to send an acknowledgment and allow that recipient to approve or reject terms and conditions. The Ask for Approval action only accepts sys_user references, not plain strings.
---
✅ Short Answer
The Ask for Approval activity cannot target a raw email string — it requires a sys_user reference.
The best approach is to create (or find) a lightweight sys_user record for that email, then use Ask for Approval so the approval is tracked in sysapproval_approver.
The external user can still approve without logging in by using tokenized approval links handled by a Scripted REST API.
---
✅ Step-by-Step Solution
1. Create Subflow: Get or Create External User (by email)
Input: email (from the catalog variable)
Logic:
- Check if a sys_user record already exists with that email.
- If not, create one (web_service_access_only = true).
- Return the sys_id for use in Ask for Approval.
Script Example:
(function execute(inputs, outputs) {
var email = (inputs.email || '').trim().toLowerCase();
if (!email) { outputs.user_sys_id = ''; return; }
var u = new GlideRecord('sys_user');
u.addQuery('email', email);
u.setLimit(1);
u.query();
if (u.next()) { outputs.user_sys_id = u.getUniqueValue(); return; }
var ext = new GlideRecord('sys_user');
ext.initialize();
ext.user_name = email;
ext.email = email;
ext.name = email;
ext.active = true;
ext.web_service_access_only = true;
outputs.user_sys_id = ext.insert();
})(inputs, outputs);
---
2. Flow Configuration
A) Step A: Call GetOrCreateExternalUserByEmail
- Input: email
- Output: approver_user_sys_id
B) Step B: Ask for Approval
- Record: your RITM (or target table)
- Approvers: approver_user_sys_id (from previous step)
- Wait for: All approvals or Anyone
C) Step C: Send Email
- Send an email to the entered address with approval/reject links that use tokens.
---
3. One-Click Tokenized Approval Links (Optional Enhancement)
Create a small table: u_approval_token
Fields: approval reference, token, action, expires_on, used
Generate unique tokens and send URLs like:
/api/x_app/approvals/oneclick?token=XYZ&action=approve
/api/x_app/approvals/oneclick?token=ABC&action=reject
Scripted REST API Example:
var appr = new GlideRecord('sysapproval_approver');
if (appr.get(token.approval) && appr.state == 'requested') {
appr.state = (action == 'approve' ? 'approved' : 'rejected');
appr.comments = 'External one-click decision';
appr.update();
token.used = true; token.update();
}
---
4. Why This Works
- Ask for Approval remains OOB and updates sysapproval_approver.
- The external person does not need login credentials.
- The lightweight user provides identity and tracking.
- Tokens ensure secure, one-time approval.
---
5. Alternatives (Less Recommended)
- Send Email action: Simplest, but loses sysapproval_approver tracking.
- Inbound Email approvals: Still requires sys_user for matching.
---
6. Security & Best Practices
- web_service_access_only = true for external users.
- Short token expiry (e.g., 48 hours).
- Store audit logs for tokens and approvals.
- Use Connection & Credential Aliases for secrets.
- Optionally deactivate users after approval is complete.
---
✅ Summary
Ask for Approval only works with sys_user references.
To support external emails:
1. Create or reuse a minimal sys_user record for the email.
2. Use Ask for Approval normally (sysapproval_approver tracking works).
3. Use tokenized links via a REST API for external, password-free approvals.
This method maintains auditability, reusability, and platform integrity.
