Email Node PII Redaction
Ensure that PII appearing in email bodies, subjects, or delivery receipts returned by the email node is redacted before the result reaches workflow logs, downstream nodes, or the caller.
The Problem
An email node processes a customer service notification. The email template is assembled from workflow data and may contain:
- The recipient's email address in the "To" field
- The customer's full name in the subject line
- A reference number that includes a phone number:
REF: +1-555-987-6543 - The SMTP delivery receipt which echoes the full message body
The email node returns an execution result that includes message metadata. This result flows into the next node and is written to the execution log. Without redaction, PII from the email body appears in both places.
The Solution: Post-Phase Redaction
PiiRedactionGuard runs in the Post phase, after the email is sent. It scans the node's output (the delivery receipt/metadata returned by the email executor), finds PII, and replaces it before the result propagates.
{
"guardRails": {
"individual": [
{
"name": "PiiRedactionGuard",
"enabled": true,
"config": {
"redaction_method": "partial", // keep first+last char: j**n@***.c*m
"fields": [] // empty = scan entire output
}
}
]
}
}
What the Redaction Does
Before redaction (raw output from email node):
{
"messageId": "msg-abc-123",
"to": "john.smith@company.com",
"subject": "Your order is confirmed",
"status": "delivered",
"deliveryReceipt": "Delivered to john.smith@company.com at 14:32:01"
}
After PiiRedactionGuard (mask method):
{
"messageId": "msg-abc-123",
"to": "**********************",
"subject": "Your order is confirmed",
"status": "delivered",
"deliveryReceipt": "Delivered to ********************** at 14:32:01"
}
After PiiRedactionGuard (partial method):
{
"messageId": "msg-abc-123",
"to": "j**************m",
"subject": "Your order is confirmed",
"status": "delivered",
"deliveryReceipt": "Delivered to j**************m at 14:32:01"
}
Why Post-Phase Only?
The email node must receive the recipient's email address to send the email — blocking it in Pre would prevent delivery. The correct pattern for email is:
- Pre phase: No PII detection (or use
enableDelayedEnforcement: trueso violations are logged but not blocked) - Post phase: PiiRedactionGuard redacts the output before it propagates
{
"guardRails": {
"individual": [
// Pre: allow input with email address (needed for delivery)
// but log that it contains PII
{
"name": "PiiDetectionGuard",
"enabled": true,
"order": 1,
"enableDelayedEnforcement": true, // log violation but do not block
"config": { "sensitivityLevel": "medium" }
},
// Post: redact PII from the email node's output/receipt
{
"name": "PiiRedactionGuard",
"enabled": true,
"config": {
"redaction_method": "partial"
}
}
]
}
}
Result Propagation
After PiiRedactionGuard runs, OutputModified=true is set. BaseNodeExecutor detects this and updates the node execution result:
// In BaseNodeExecutor.OnPostGuardRails():
var postResult = await _guardExecutor.ExecutePostAsync(guardContext, nodeResult.OutputData);
if (postResult.OutputModified)
{
// The redacted output replaces the original
nodeResult.OutputData = guardContext.Output;
}
The downstream node and execution log receive the redacted version. The raw email address never appears outside the email delivery layer.
PiiRedactionGuard applies redactions from end to start of the string (reverse position order). This preserves string offsets — earlier redactions don't shift the positions used by later ones.