Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Ask for Approval Activity does not take string value for user email.

saint
Tera Expert

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!

2 REPLIES 2

MaxMixali
Giga Guru

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.

 

 

MaxMixali
Giga Guru

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.