feat(sms): draft envelope + Docusign Sender View for recipients without email

When the primary recipient (Docusign Recipient #1) has no email address, the
envelope is created in draft status and the sender completes delivery manually
in the Docusign Sender View web console where they can configure SMS delivery.

Apex changes:
- DocusignCompositeEnvelopeBuilder: new DRAFT_PLACEHOLDER_EMAIL constant; when
  requiresDraftMode=true calls sendEnvelope(envelope, false) to create a draft,
  then builds and returns a Sender View URL via buildSenderViewUrl(); buildRecipient
  accepts allowPlaceholderEmail flag and substitutes placeholder when email is blank
- DocusignEnvelopeRequest: new requiresDraftMode Boolean InvocableVariable
- DocusignEnvelopeResult: new senderViewUrl String InvocableVariable

Flow (V3) changes:
- Get_Records now fetches Docusign_Recipient_1__c
- New Get_Recipient_Contact lookup queries Contact.Email and Name
- New Is_Recipient_Email_Blank decision routes to Set_Draft_Mode when blank
- New Set_Draft_Mode assignment sets requiresDraftMode=true
- New No_Email_Warning_Screen explains the draft process and required steps
- requiresDraftMode passed as input; senderViewUrl captured as output
- New Is_Draft_Envelope decision routes to Sender_View_Screen or Success_Screen
- New Sender_View_Screen shows clickable link, placeholder email, and step-by-step
  instructions for configuring SMS delivery in the Docusign web console
This commit is contained in:
Paul Huliganga 2026-03-13 00:05:02 -04:00
parent 86e7d2fb62
commit 40798dfe63
4 changed files with 982 additions and 12 deletions

View File

@ -28,6 +28,17 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
// ============================================================
@TestVisible
private static final String MULTI_COPY_TEMPLATE_NAME = 'Authorization to Release Information';
// ============================================================
// DRAFT MODE / SENDER VIEW: When the primary recipient has no email
// and requiresDraftMode=true, the envelope is created in draft status.
// Docusign requires an email address on every recipient even in draft
// mode, so this placeholder satisfies the API requirement.
// The sender will replace this with the real SMS recipient details
// manually in the Docusign Sender View before sending.
// ============================================================
@TestVisible
private static final String DRAFT_PLACEHOLDER_EMAIL = 'placeholder_email@docusign.com';
@InvocableMethod(
label='Send Composite Docusign Envelope'
@ -188,7 +199,7 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
}
// Resolve recipients from Client_Case__c lookup fields
List<dfsle.Recipient> recipients = resolveRecipients(req.recordId);
List<dfsle.Recipient> recipients = resolveRecipients(req.recordId, draftMode);
myEnvelope = myEnvelope.withRecipients(recipients);
// Set envelope subject to combined display names (deduplicated, with copy counts).
@ -222,15 +233,29 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
String envelopeBody = bodyParts.isEmpty() ? '' : String.join(bodyParts, '\n\n');
myEnvelope = myEnvelope.withEmail(envelopeSubject, envelopeBody);
// Send the envelope
myEnvelope = dfsle.EnvelopeService.sendEnvelope(myEnvelope, true);
// Send the envelope — or create it as a draft when requiresDraftMode is true.
//
// Draft mode is used when the primary recipient has no email address and will
// need SMS delivery configured manually in the Docusign Sender View.
// dfsle.EnvelopeService.sendEnvelope(envelope, false) creates the envelope in
// "created" (draft) status without sending it. We then build the Sender View
// URL so the flow can present a direct link to the Docusign web console.
Boolean draftMode = (req.requiresDraftMode == true);
myEnvelope = dfsle.EnvelopeService.sendEnvelope(myEnvelope, !draftMode);
// Success
result.envelopeId = String.valueOf(myEnvelope.docuSignId);
result.success = true;
result.errorMessage = null;
logResult(sortedTemplateIds.size(), result.envelopeId, 'Success (' + String.join(displayNames, ', ') + ')', null);
if (draftMode) {
result.senderViewUrl = buildSenderViewUrl(result.envelopeId);
logResult(sortedTemplateIds.size(), result.envelopeId,
'Draft created — Sender View required (' + String.join(displayNames, ', ') + ')', null);
} else {
result.senderViewUrl = null;
logResult(sortedTemplateIds.size(), result.envelopeId,
'Success (' + String.join(displayNames, ', ') + ')', null);
}
} catch (Exception e) {
result.success = false;
@ -256,9 +281,12 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
* @description Resolves recipients from Client_Case__c lookup fields.
* Queries the case record and related contacts to get name/email.
* @param recordId The Client_Case__c record ID
* @param draftMode When true, a missing email on the primary recipient is allowed
* DRAFT_PLACEHOLDER_EMAIL is substituted so the dfsle call succeeds.
* The sender will update the recipient in the Docusign Sender View.
* @return List of dfsle.Recipient objects with role mappings
*/
private static List<dfsle.Recipient> resolveRecipients(String recordId) {
private static List<dfsle.Recipient> resolveRecipients(String recordId, Boolean draftMode) {
// Query the Client_Case__c record with recipient lookup fields
// NOTE: Adjust field API names if they differ in your org
String query = 'SELECT Id, '
@ -274,13 +302,13 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
// Recipient 1: Service Coordinator
Id serviceCoordinatorId = (Id) caseRecord.get(FIELD_SERVICE_COORDINATOR);
if (serviceCoordinatorId != null) {
recipients.add(buildRecipient(serviceCoordinatorId, ROLE_SERVICE_COORDINATOR, routingOrder++, recordId));
recipients.add(buildRecipient(serviceCoordinatorId, ROLE_SERVICE_COORDINATOR, routingOrder++, recordId, false));
}
// Recipient 2: Docusign Recipient #1
Id docusignRecipientId = (Id) caseRecord.get(FIELD_DOCUSIGN_RECIPIENT);
if (docusignRecipientId != null) {
recipients.add(buildRecipient(docusignRecipientId, ROLE_DOCUSIGN_RECIPIENT, routingOrder++, recordId));
recipients.add(buildRecipient(docusignRecipientId, ROLE_DOCUSIGN_RECIPIENT, routingOrder++, recordId, draftMode));
}
if (recipients.isEmpty()) {
@ -297,9 +325,12 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
* @param roleName The Docusign template role name
* @param routingOrder Signing order
* @param sourceRecordId The source Client_Case__c record ID
* @param allowPlaceholderEmail When true and the recipient has no email, substitutes
* DRAFT_PLACEHOLDER_EMAIL so the dfsle call succeeds.
* Only set true for the primary recipient in draft mode.
* @return dfsle.Recipient configured for the role
*/
private static dfsle.Recipient buildRecipient(Id recipientId, String roleName, Integer routingOrder, String sourceRecordId) {
private static dfsle.Recipient buildRecipient(Id recipientId, String roleName, Integer routingOrder, String sourceRecordId, Boolean allowPlaceholderEmail) {
// Determine if this is a Contact or User
String objectType = recipientId.getSObjectType().getDescribe().getName();
@ -320,8 +351,14 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
}
if (String.isBlank(recipientEmail)) {
throw new IllegalArgumentException('No email found for ' + roleName + ' (' + recipientName + '). '
+ 'Please ensure the recipient has a valid email address.');
if (allowPlaceholderEmail == true) {
// Draft mode — substitute placeholder so the envelope can be created.
// The sender will update this recipient's details in the Docusign Sender View.
recipientEmail = DRAFT_PLACEHOLDER_EMAIL;
} else {
throw new IllegalArgumentException('No email found for ' + roleName + ' (' + recipientName + '). '
+ 'Please ensure the recipient has a valid email address.');
}
}
return dfsle.Recipient.fromSource(
@ -342,6 +379,58 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
System.debug(LoggingLevel.ERROR, 'Error: ' + errorMessage);
}
}
/**
* @description Builds the Docusign Sender View URL for a draft envelope.
* The URL opens the envelope in the Docusign web console so the sender
* can configure SMS delivery and send it manually.
*
* URL format:
* Production: https://app.docusign.com/documents/details/{envelopeId}
* Demo/sandbox: https://app.docusign.net/documents/details/{envelopeId}
*
* Base_URL__c on the Docusign_Configuration__c custom setting stores the
* callout base URL (e.g. https://demo.docusign.net/restapi or
* https://na3.docusign.net/restapi). We derive the web console host from
* that so the link always points to the correct environment.
*
* @param envelopeId The Docusign envelope ID (GUID) of the draft envelope
* @return Full Sender View URL string
*/
@TestVisible
private static String buildSenderViewUrl(String envelopeId) {
// Determine the web console host from Base_URL__c.
// Base_URL__c looks like: https://demo.docusign.net/restapi
// or: https://na3.docusign.net/restapi
// We extract the scheme + host and append the documents/details path.
String webHost = 'https://app.docusign.com'; // default: production
try {
Docusign_Configuration__c config = Docusign_Configuration__c.getInstance();
if (config != null && String.isNotBlank(config.Base_URL__c)) {
String baseUrl = config.Base_URL__c.trim();
// Strip trailing path components to get just scheme://host
Integer restApiIdx = baseUrl.toLowerCase().indexOf('/restapi');
if (restApiIdx > 0) {
baseUrl = baseUrl.left(restApiIdx);
}
// Replace API host with web console host:
// demo.docusign.net → app.docusign.net (sandbox/demo)
// *.docusign.net → app.docusign.net (other NA/EU pods)
// app.docusign.com → app.docusign.com (production)
if (baseUrl.containsIgnoreCase('demo.docusign')) {
webHost = 'https://app.docusign.net';
} else if (baseUrl.containsIgnoreCase('.docusign.net')) {
webHost = 'https://app.docusign.net';
} else {
webHost = 'https://app.docusign.com';
}
}
} catch (Exception ex) {
// If config lookup fails, fall back to production URL
System.debug(LoggingLevel.WARN, 'Could not read Base_URL__c for Sender View URL: ' + ex.getMessage());
}
return webHost + '/documents/details/' + envelopeId;
}
/**
* @description Strips language suffixes like " - English" or " - Spanish" from template names

View File

@ -39,4 +39,11 @@ global class DocusignEnvelopeRequest {
required=false
)
global Integer authReleaseFormCopies;
@InvocableVariable(
label='Requires Draft Mode'
description='When true, the envelope is created in draft (created) status instead of being sent immediately. Used when the primary recipient has no email address and SMS delivery must be configured manually in the Docusign Sender View. The result will contain a senderViewUrl the user should open to complete sending.'
required=false
)
global Boolean requiresDraftMode;
}

View File

@ -22,4 +22,10 @@ global class DocusignEnvelopeResult {
description='Error message if envelope creation failed'
)
global String errorMessage;
@InvocableVariable(
label='Sender View URL'
description='Docusign Sender View URL. Populated when the envelope was created as a draft because the primary recipient has no email address. The user must open this URL in the Docusign web console to configure SMS delivery and send the envelope manually.'
)
global String senderViewUrl;
}

View File

@ -0,0 +1,868 @@
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<actionCalls>
<name>Send_Composite_Envelope</name>
<label>Send Composite Envelope</label>
<locationX>182</locationX>
<locationY>1082</locationY>
<actionName>DocusignCompositeEnvelopeBuilder</actionName>
<actionType>apex</actionType>
<connector>
<targetReference>Check_Envelope_Result</targetReference>
</connector>
<flowTransactionModel>Automatic</flowTransactionModel>
<inputParameters>
<name>templateIds</name>
<value>
<elementReference>compositeTemplateIds</elementReference>
</value>
</inputParameters>
<inputParameters>
<name>recordId</name>
<value>
<elementReference>recordId</elementReference>
</value>
</inputParameters>
<inputParameters>
<name>language</name>
<value>
<elementReference>Get_Records.Docusign_Envelope_Language__c</elementReference>
</value>
</inputParameters>
<inputParameters>
<name>authReleaseFormCopies</name>
<value>
<elementReference>authReleaseFormCopies</elementReference>
</value>
</inputParameters>
<inputParameters>
<name>requiresDraftMode</name>
<value>
<elementReference>requiresDraftMode</elementReference>
</value>
</inputParameters>
<nameSegment>DocusignCompositeEnvelopeBuilder</nameSegment>
<offset>0</offset>
<outputParameters>
<assignToReference>envelopeId</assignToReference>
<name>envelopeId</name>
</outputParameters>
<outputParameters>
<assignToReference>envelopeSuccess</assignToReference>
<name>success</name>
</outputParameters>
<outputParameters>
<assignToReference>envelopeErrorMessage</assignToReference>
<name>errorMessage</name>
</outputParameters>
<outputParameters>
<assignToReference>senderViewUrl</assignToReference>
<name>senderViewUrl</name>
</outputParameters>
</actionCalls>
<apiVersion>60.0</apiVersion>
<areMetricsLoggedToDataCloud>false</areMetricsLoggedToDataCloud>
<assignments>
<name>Add_Template_ID</name>
<label>Add Template ID</label>
<locationX>270</locationX>
<locationY>1106</locationY>
<assignmentItems>
<assignToReference>compositeTemplateIds</assignToReference>
<operator>Add</operator>
<value>
<elementReference>Build_Template_ID_Collection.dfsle__DocuSignId__c</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Build_Template_ID_Collection</targetReference>
</connector>
</assignments>
<assignments>
<name>Flag_Auth_Release_Selected</name>
<label>Flag Authorization to Release Template Selected</label>
<locationX>270</locationX>
<locationY>1000</locationY>
<assignmentItems>
<assignToReference>authReleaseTemplateSelected</assignToReference>
<operator>Assign</operator>
<value>
<booleanValue>true</booleanValue>
</value>
</assignmentItems>
<connector>
<targetReference>Scan_For_Auth_Release_Template</targetReference>
</connector>
</assignments>
<assignments>
<name>Store_Auth_Release_Copies</name>
<label>Store Authorization to Release Copies Selection</label>
<locationX>182</locationX>
<locationY>1160</locationY>
<assignmentItems>
<assignToReference>authReleaseFormCopies</assignToReference>
<operator>Assign</operator>
<value>
<elementReference>authReleaseFormCopies_Radio</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Build_Template_ID_Collection</targetReference>
</connector>
</assignments>
<decisions>
<name>Check_Envelope_Result</name>
<label>Check Envelope Result</label>
<locationX>182</locationX>
<locationY>1190</locationY>
<defaultConnector>
<targetReference>Error_Screen</targetReference>
</defaultConnector>
<defaultConnectorLabel>Default Outcome</defaultConnectorLabel>
<rules>
<name>Envelope_Sent_Successfully</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>envelopeSuccess</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Is_Draft_Envelope</targetReference>
</connector>
<label>Envelope Sent Successfully</label>
</rules>
</decisions>
<decisions>
<name>Check_Row_Selection</name>
<label>Check Row Selection</label>
<locationX>380</locationX>
<locationY>674</locationY>
<defaultConnector>
<targetReference>Row_not_selected</targetReference>
</defaultConnector>
<defaultConnectorLabel>Default Outcome</defaultConnectorLabel>
<rules>
<name>Is_Row_Selected</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>data.firstSelectedRow.Id</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>false</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Scan_For_Auth_Release_Template</targetReference>
</connector>
<label>Is Row Selected?</label>
</rules>
</decisions>
<decisions>
<name>Is_Auth_Release_Selected</name>
<label>Is Authorization to Release Info Selected?</label>
<locationX>380</locationX>
<locationY>890</locationY>
<defaultConnector>
<targetReference>Build_Template_ID_Collection</targetReference>
</defaultConnector>
<defaultConnectorLabel>No - Proceed</defaultConnectorLabel>
<rules>
<name>Auth_Release_Template_Found</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>authReleaseTemplateSelected</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Authorization_Copies_Screen</targetReference>
</connector>
<label>Yes - Ask for copies</label>
</rules>
</decisions>
<decisions>
<name>Is_Language_Selected</name>
<label>Is Language Selected?</label>
<locationX>611</locationX>
<locationY>458</locationY>
<defaultConnector>
<targetReference>Language_Not_Added_Screen</targetReference>
</defaultConnector>
<defaultConnectorLabel>Default Outcome</defaultConnectorLabel>
<rules>
<name>Language_Selected</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>Get_Records.Docusign_Envelope_Language__c</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>false</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Language_Warning_Screen</targetReference>
</connector>
<label>Language Selected?</label>
</rules>
</decisions>
<decisions>
<name>Does_Row_Contain_Auth_Release</name>
<label>Does This Row Contain Authorization to Release Info?</label>
<locationX>270</locationX>
<locationY>890</locationY>
<defaultConnector>
<targetReference>Scan_For_Auth_Release_Template</targetReference>
</defaultConnector>
<defaultConnectorLabel>No</defaultConnectorLabel>
<rules>
<name>Row_Is_Auth_Release_Template</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>Scan_For_Auth_Release_Template.Name</leftValueReference>
<operator>Contains</operator>
<rightValue>
<stringValue>Authorization to Release Information</stringValue>
</rightValue>
</conditions>
<connector>
<targetReference>Flag_Auth_Release_Selected</targetReference>
</connector>
<label>Yes</label>
</rules>
</decisions>
<recordLookups>
<name>Get_Recipient_Contact</name>
<label>Get Recipient Contact</label>
<locationX>611</locationX>
<locationY>242</locationY>
<assignNullValuesIfNoRecordsFound>true</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Is_Recipient_Email_Blank</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>Id</field>
<operator>EqualTo</operator>
<value>
<elementReference>Get_Records.Docusign_Recipient_1__c</elementReference>
</value>
</filters>
<getFirstRecordOnly>true</getFirstRecordOnly>
<object>Contact</object>
<queriedFields>Id</queriedFields>
<queriedFields>Email</queriedFields>
<queriedFields>Name</queriedFields>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>
<decisions>
<name>Is_Recipient_Email_Blank</name>
<label>Is Recipient Email Blank?</label>
<locationX>611</locationX>
<locationY>350</locationY>
<defaultConnector>
<targetReference>Is_Language_Selected</targetReference>
</defaultConnector>
<defaultConnectorLabel>Has Email - Continue</defaultConnectorLabel>
<rules>
<name>Recipient_Has_No_Email</name>
<conditionLogic>or</conditionLogic>
<conditions>
<leftValueReference>Get_Recipient_Contact.Email</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions>
<conditions>
<leftValueReference>Get_Recipient_Contact.Email</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue></stringValue>
</rightValue>
</conditions>
<connector>
<targetReference>Set_Draft_Mode</targetReference>
</connector>
<label>No Email - Draft Mode Required</label>
</rules>
</decisions>
<assignments>
<name>Set_Draft_Mode</name>
<label>Set Draft Mode Flag</label>
<locationX>842</locationX>
<locationY>350</locationY>
<assignmentItems>
<assignToReference>requiresDraftMode</assignToReference>
<operator>Assign</operator>
<value>
<booleanValue>true</booleanValue>
</value>
</assignmentItems>
<connector>
<targetReference>No_Email_Warning_Screen</targetReference>
</connector>
</assignments>
<screens>
<name>No_Email_Warning_Screen</name>
<label>Recipient Has No Email — SMS Delivery Required</label>
<locationX>842</locationX>
<locationY>458</locationY>
<allowBack>false</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<connector>
<targetReference>Is_Language_Selected</targetReference>
</connector>
<fields>
<name>NoEmailWarningText</name>
<fieldText>&lt;p&gt;⚠️ &lt;strong&gt;The primary recipient does not have an email address on file.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Because Docusign requires an email address to create an envelope, a &lt;strong&gt;draft envelope&lt;/strong&gt; will be created using a placeholder email address (&lt;strong&gt;placeholder_email@docusign.com&lt;/strong&gt;). You will then be taken to the Docusign web console to complete sending.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Once in the Docusign Sender View you must:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find the recipient &lt;strong&gt;{!Get_Recipient_Contact.Name}&lt;/strong&gt; (currently showing placeholder_email@docusign.com).&lt;/li&gt;
&lt;li&gt;Edit the recipient and &lt;strong&gt;enable SMS delivery&lt;/strong&gt; for that recipient.&lt;/li&gt;
&lt;li&gt;Enter the recipient&apos;s &lt;strong&gt;mobile phone number&lt;/strong&gt; for SMS delivery.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Send&lt;/strong&gt; to dispatch the envelope.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;Next&lt;/strong&gt; to proceed to template selection.&lt;/p&gt;</fieldText>
<fieldType>DisplayText</fieldType>
<styleProperties>
<verticalAlignment>
<stringValue>top</stringValue>
</verticalAlignment>
<width>
<stringValue>12</stringValue>
</width>
</styleProperties>
</fields>
<nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>
<showFooter>true</showFooter>
<showHeader>true</showHeader>
</screens>
<decisions>
<name>Is_Draft_Envelope</name>
<label>Is This a Draft Envelope?</label>
<locationX>182</locationX>
<locationY>1298</locationY>
<defaultConnector>
<targetReference>Success_Screen</targetReference>
</defaultConnector>
<defaultConnectorLabel>No — Sent Normally</defaultConnectorLabel>
<rules>
<name>Draft_Envelope_Created</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>senderViewUrl</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>false</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Sender_View_Screen</targetReference>
</connector>
<label>Yes — Open Sender View</label>
</rules>
</decisions>
<screens>
<name>Sender_View_Screen</name>
<label>Open Envelope in Docusign Sender View</label>
<locationX>314</locationX>
<locationY>1406</locationY>
<allowBack>false</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<fields>
<name>SenderViewInstructions</name>
<fieldText>&lt;p&gt;&lt;strong&gt;Draft envelope created successfully.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Envelope ID:&lt;/strong&gt; {!envelopeId}&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;The envelope has been saved as a &lt;strong&gt;draft&lt;/strong&gt; because the primary recipient &lt;strong&gt;{!Get_Recipient_Contact.Name}&lt;/strong&gt; has no email address. You must complete sending in the Docusign web console.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps to complete:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click the link below to open the envelope in the &lt;strong&gt;Docusign Sender View&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Find the recipient showing &lt;strong&gt;placeholder_email@docusign.com&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Edit that recipient — enable &lt;strong&gt;SMS delivery&lt;/strong&gt; and enter their mobile phone number.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Send&lt;/strong&gt; in Docusign to dispatch the envelope.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;🔗 &lt;a href=&quot;{!senderViewUrl}&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;Open Envelope in Docusign&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If the link does not open, copy and paste this URL into your browser:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;{!senderViewUrl}&lt;/p&gt;</fieldText>
<fieldType>DisplayText</fieldType>
<styleProperties>
<verticalAlignment>
<stringValue>top</stringValue>
</verticalAlignment>
<width>
<stringValue>12</stringValue>
</width>
</styleProperties>
</fields>
<showFooter>true</showFooter>
<showHeader>false</showHeader>
</screens>
<environments>Default</environments>
<interviewLabel>Docusign Envelope Templates V4 {!$Flow.CurrentDateTime}</interviewLabel>
<label>Docusign Envelope Templates V4</label>
<loops>
<name>Build_Template_ID_Collection</name>
<label>Build Template ID Collection</label>
<locationX>182</locationX>
<locationY>1214</locationY>
<collectionReference>data.selectedRows</collectionReference>
<iterationOrder>Asc</iterationOrder>
<nextValueConnector>
<targetReference>Add_Template_ID</targetReference>
</nextValueConnector>
<noMoreValuesConnector>
<targetReference>Send_Composite_Envelope</targetReference>
</noMoreValuesConnector>
</loops>
<loops>
<name>Scan_For_Auth_Release_Template</name>
<label>Scan For Authorization to Release Template</label>
<locationX>380</locationX>
<locationY>782</locationY>
<collectionReference>data.selectedRows</collectionReference>
<iterationOrder>Asc</iterationOrder>
<nextValueConnector>
<targetReference>Does_Row_Contain_Auth_Release</targetReference>
</nextValueConnector>
<noMoreValuesConnector>
<targetReference>Is_Auth_Release_Selected</targetReference>
</noMoreValuesConnector>
</loops>
<processMetadataValues>
<name>BuilderType</name>
<value>
<stringValue>LightningFlowBuilder</stringValue>
</value>
</processMetadataValues>
<processMetadataValues>
<name>CanvasMode</name>
<value>
<stringValue>AUTO_LAYOUT_CANVAS</stringValue>
</value>
</processMetadataValues>
<processMetadataValues>
<name>OriginBuilderType</name>
<value>
<stringValue>LightningFlowBuilder</stringValue>
</value>
</processMetadataValues>
<processType>Flow</processType>
<recordLookups>
<name>DocuSign_Envelope_Templates</name>
<label>DocuSign Envelope Templates</label>
<locationX>380</locationX>
<locationY>458</locationY>
<assignNullValuesIfNoRecordsFound>false</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Envelope_template_records</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>Envelope_Template_Language__c</field>
<operator>EqualTo</operator>
<value>
<elementReference>Get_Records.Docusign_Envelope_Language__c</elementReference>
</value>
</filters>
<filters>
<field>Short_Name__c</field>
<operator>IsNull</operator>
<value>
<booleanValue>false</booleanValue>
</value>
</filters>
<getFirstRecordOnly>false</getFirstRecordOnly>
<object>dfsle__EnvelopeConfiguration__c</object>
<queriedFields>Id</queriedFields>
<queriedFields>Name</queriedFields>
<queriedFields>dfsle__DocuSignId__c</queriedFields>
<sortField>Name</sortField>
<sortOrder>Asc</sortOrder>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>
<recordLookups>
<name>Get_Records</name>
<label>Get Records</label>
<locationX>611</locationX>
<locationY>134</locationY>
<assignNullValuesIfNoRecordsFound>false</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Get_Recipient_Contact</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>Id</field>
<operator>EqualTo</operator>
<value>
<elementReference>recordId</elementReference>
</value>
</filters>
<getFirstRecordOnly>true</getFirstRecordOnly>
<object>Client_Case__c</object>
<queriedFields>Id</queriedFields>
<queriedFields>Docusign_Envelope_Language__c</queriedFields>
<queriedFields>Docusign_Recipient_1__c</queriedFields>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>
<screens>
<name>Envelope_template_records</name>
<label>Envelope template records</label>
<locationX>380</locationX>
<locationY>566</locationY>
<allowBack>true</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<backButtonLabel>Back</backButtonLabel>
<connector>
<targetReference>Check_Row_Selection</targetReference>
</connector>
<fields>
<name>data</name>
<dataTypeMappings>
<typeName>T</typeName>
<typeValue>dfsle__EnvelopeConfiguration__c</typeValue>
</dataTypeMappings>
<extensionName>flowruntime:datatable</extensionName>
<fieldType>ComponentInstance</fieldType>
<inputParameters>
<name>label</name>
<value>
<stringValue>Select Templates for Composite Envelope</stringValue>
</value>
</inputParameters>
<inputParameters>
<name>selectionMode</name>
<value>
<stringValue>MULTI_SELECT</stringValue>
</value>
</inputParameters>
<inputParameters>
<name>minRowSelection</name>
<value>
<numberValue>0.0</numberValue>
</value>
</inputParameters>
<inputParameters>
<name>tableData</name>
<value>
<elementReference>DocuSign_Envelope_Templates</elementReference>
</value>
</inputParameters>
<inputParameters>
<name>columns</name>
<value>
<stringValue>[{&quot;apiName&quot;:&quot;Name&quot;,&quot;guid&quot;:&quot;column-6d57&quot;,&quot;editable&quot;:false,&quot;hasCustomHeaderLabel&quot;:true,&quot;customHeaderLabel&quot;:&quot;Envelope Template Name&quot;,&quot;wrapText&quot;:true,&quot;order&quot;:0,&quot;label&quot;:&quot;Name&quot;,&quot;type&quot;:&quot;text&quot;}]</stringValue>
</value>
</inputParameters>
<inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
<isRequired>true</isRequired>
<storeOutputAutomatically>true</storeOutputAutomatically>
<styleProperties>
<verticalAlignment>
<stringValue>top</stringValue>
</verticalAlignment>
<width>
<stringValue>12</stringValue>
</width>
</styleProperties>
</fields>
<nextOrFinishButtonLabel>Send</nextOrFinishButtonLabel>
<showFooter>true</showFooter>
<showHeader>true</showHeader>
</screens>
<screens>
<name>Authorization_Copies_Screen</name>
<label>Authorization to Release Info - Number of Copies</label>
<locationX>182</locationX>
<locationY>1106</locationY>
<allowBack>true</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<backButtonLabel>Back</backButtonLabel>
<connector>
<targetReference>Store_Auth_Release_Copies</targetReference>
</connector>
<fields>
<name>AuthCopiesHeader</name>
<fieldText>&lt;p&gt;The &lt;strong&gt;Authorization to Release Information&lt;/strong&gt; form was selected.&lt;/p&gt;&lt;p&gt;How many copies of this form should be included in the envelope?&lt;/p&gt;</fieldText>
<fieldType>DisplayText</fieldType>
<styleProperties>
<verticalAlignment>
<stringValue>top</stringValue>
</verticalAlignment>
<width>
<stringValue>12</stringValue>
</width>
</styleProperties>
</fields>
<fields>
<name>authReleaseFormCopies_Radio</name>
<choiceReferences>AuthCopies_1</choiceReferences>
<choiceReferences>AuthCopies_2</choiceReferences>
<choiceReferences>AuthCopies_3</choiceReferences>
<dataType>Number</dataType>
<defaultSelectedChoiceReference>AuthCopies_1</defaultSelectedChoiceReference>
<fieldText>Number of Copies</fieldText>
<fieldType>RadioButtons</fieldType>
<isRequired>true</isRequired>
<scale>0</scale>
<styleProperties>
<verticalAlignment>
<stringValue>top</stringValue>
</verticalAlignment>
<width>
<stringValue>12</stringValue>
</width>
</styleProperties>
</fields>
<nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>
<showFooter>true</showFooter>
<showHeader>true</showHeader>
</screens>
<screens>
<name>Error_Screen</name>
<label>Error Screen</label>
<locationX>314</locationX>
<locationY>1298</locationY>
<allowBack>true</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<backButtonLabel>Back</backButtonLabel>
<fields>
<name>ErrorDisplayMessage</name>
<fieldText>&lt;p&gt;&lt;span style=&quot;font-size: 16px; color: rgb(255, 0, 0);&quot;&gt;❌ Failed to send composite envelope.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Error:&lt;/strong&gt; {!envelopeErrorMessage}&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;Please try again or contact your administrator.&lt;/p&gt;</fieldText>
<fieldType>DisplayText</fieldType>
<styleProperties>
<verticalAlignment>
<stringValue>top</stringValue>
</verticalAlignment>
<width>
<stringValue>12</stringValue>
</width>
</styleProperties>
</fields>
<showFooter>true</showFooter>
<showHeader>false</showHeader>
</screens>
<screens>
<name>Language_Not_Added_Screen</name>
<label>Language Not Added Screen</label>
<locationX>842</locationX>
<locationY>350</locationY>
<allowBack>false</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<fields>
<name>LanguageNotSelected</name>
<fieldText>&lt;p&gt;The &lt;strong&gt;DocuSign Envelope Language&lt;/strong&gt; is not populated on the record. Please add the language first and then proceed.&lt;/p&gt;</fieldText>
<fieldType>DisplayText</fieldType>
<styleProperties>
<verticalAlignment>
<stringValue>top</stringValue>
</verticalAlignment>
<width>
<stringValue>12</stringValue>
</width>
</styleProperties>
</fields>
<showFooter>true</showFooter>
<showHeader>true</showHeader>
</screens>
<screens>
<name>Language_Warning_Screen</name>
<label>Language Warning Screen</label>
<locationX>380</locationX>
<locationY>350</locationY>
<allowBack>false</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<connector>
<targetReference>DocuSign_Envelope_Templates</targetReference>
</connector>
<fields>
<name>LangWarningText</name>
<fieldText>&lt;p&gt;The current selected language is &lt;strong&gt;{!Get_Records.Docusign_Envelope_Language__c}. &lt;/strong&gt;On the next screen you will be able to see form names of {!Get_Records.Docusign_Envelope_Language__c} language only. If you want to switch the language, please go back to record and select another language form &lt;strong&gt;DocuSign Envelope Language&lt;/strong&gt;.&lt;/p&gt;</fieldText>
<fieldType>DisplayText</fieldType>
<styleProperties>
<verticalAlignment>
<stringValue>top</stringValue>
</verticalAlignment>
<width>
<stringValue>12</stringValue>
</width>
</styleProperties>
</fields>
<nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>
<showFooter>true</showFooter>
<showHeader>true</showHeader>
</screens>
<screens>
<name>Row_not_selected</name>
<label>Row not selected</label>
<locationX>578</locationX>
<locationY>782</locationY>
<allowBack>true</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<backButtonLabel>Back</backButtonLabel>
<fields>
<name>ErrorMessage</name>
<fieldText>&lt;p&gt;&lt;strong style=&quot;background-color: rgb(255, 255, 255); color: rgb(68, 68, 68);&quot;&gt;&lt;em&gt;You have not selected any of the forms. Please go back and select the form first and then proceed.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;</fieldText>
<fieldType>DisplayText</fieldType>
<styleProperties>
<verticalAlignment>
<stringValue>top</stringValue>
</verticalAlignment>
<width>
<stringValue>12</stringValue>
</width>
</styleProperties>
</fields>
<showFooter>true</showFooter>
<showHeader>false</showHeader>
</screens>
<screens>
<name>Success_Screen</name>
<label>Success Screen</label>
<locationX>50</locationX>
<locationY>1298</locationY>
<allowBack>false</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<fields>
<name>SuccessMessage</name>
<fieldText>&lt;p&gt;&lt;span style=&quot;font-size: 16px; color: rgb(0, 128, 0);&quot;&gt;✅ Composite envelope sent successfully!&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Envelope ID:&lt;/strong&gt; {!envelopeId}&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Templates combined:&lt;/strong&gt; All selected templates were merged into a single envelope.&lt;/p&gt;</fieldText>
<fieldType>DisplayText</fieldType>
<styleProperties>
<verticalAlignment>
<stringValue>top</stringValue>
</verticalAlignment>
<width>
<stringValue>12</stringValue>
</width>
</styleProperties>
</fields>
<showFooter>true</showFooter>
<showHeader>false</showHeader>
</screens>
<start>
<locationX>485</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Get_Records</targetReference>
</connector>
</start>
<status>Draft</status>
<variables>
<name>compositeTemplateIds</name>
<dataType>String</dataType>
<isCollection>true</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>envelopeErrorMessage</name>
<dataType>String</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>envelopeId</name>
<dataType>String</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>envelopeSuccess</name>
<dataType>Boolean</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>recordId</name>
<dataType>String</dataType>
<isCollection>false</isCollection>
<isInput>true</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>authReleaseFormCopies</name>
<dataType>Number</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
<scale>0</scale>
<value>
<numberValue>1.0</numberValue>
</value>
</variables>
<variables>
<name>authReleaseTemplateSelected</name>
<dataType>Boolean</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
<value>
<booleanValue>false</booleanValue>
</value>
</variables>
<variables>
<name>requiresDraftMode</name>
<dataType>Boolean</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
<value>
<booleanValue>false</booleanValue>
</value>
</variables>
<variables>
<name>senderViewUrl</name>
<dataType>String</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
</variables>
<choices>
<name>AuthCopies_1</name>
<choiceText>1 copy</choiceText>
<dataType>Number</dataType>
<value>
<numberValue>1.0</numberValue>
</value>
</choices>
<choices>
<name>AuthCopies_2</name>
<choiceText>2 copies</choiceText>
<dataType>Number</dataType>
<value>
<numberValue>2.0</numberValue>
</value>
</choices>
<choices>
<name>AuthCopies_3</name>
<choiceText>3 copies</choiceText>
<dataType>Number</dataType>
<value>
<numberValue>3.0</numberValue>
</value>
</choices>
</Flow>