Docusign - How To - How to request a signature by email

How to request a signature by email

This topic demonstrates how to send a signature request via an email, also known as a remote signature request or remote signing. The email will contain a signing link that the recipient can use to open and electronically sign a document using the Docusign mobile app or the Docusign website. After signing is complete, the recipient receives a carbon copy (CC) of the email that includes all of the completed and signed documents.

This example scenario also demonstrates how to:

  1. Use anchor tabs to automatically position tabs in documents at instances of a specified string.
  2. Include signing documents in several formats (a customized HTML file, a DOCX file, opens in new window, and a PDF filePDF file, opens in new window in the envelope).

Required data

Running the code in this how-to requires this data:

DATA ELEMENT DESCRIPTION
{API_ACCOUNT_ID} A GUID, opens in new window value that identifies your account. This value is automatically generated by Docusign for any account you create. Copy the value from the API Account ID field on the Apps and KeysApps and Keys, opens in new window page.
{BASE_PATH} A string value that forms the root of the URL required to make API calls. The base path value in the example code is set to target the developer environment at https:///restapi
Where is demo.docusign.net for the developer environment and is the result of the GetUserInfo call in production.
Documents to be signed You must provide at least one document to be signed. Documents used in this how-to: DOCX file, opens in new window, PDF file, opens in new window
A third document in HTML is constructed dynamically by the sample code
{SIGNER_EMAIL} A string value for the email address where the signer will receive a notification of the signing request.
{SIGNER_NAME} A string value for the full name of the signer.

Step 1. Obtain your OAuth token

To make the API call shown in this how-to, you need a valid OAuth access token. Docusign supports access tokens for three different OAuth grant types: Authorization Code Grant, Implicit Grant, and JSON Web Token (JWT) Grant. Choose the OAuth grant type appropriate for your scenario.

Step 2. Create the envelope definition

The first step in requesting a signature by email is to create a new envelope definition. This topic shows how to create an individual envelope by defining a method named makeEnvelope that creates the envelope definition. The makeEnvelope method demonstrates how to:

  • Create a new, signable HTML document in code.
  • Attach multiple documents to the envelope.
  • Set signer and CC recipient data.
  • Create a routing order for the documents.
  • Create and assign signable fields to specific signers within the documents.

Define the makeEnvelope method with this code.

  1. Python
def make_envelope(cls, args, doc_docx_path, doc_pdf_path):
    """
    Creates envelope
    Document 1: An HTML document.
    Document 2: A Word .docx document.
    Document 3: A PDF document.
    DocuSign will convert all of the documents to the PDF format.
    The recipients" field tags are placed using <b>anchor</b> strings.
    """

    # document 1 (html) has sign here anchor tag **signature_1**
    # document 2 (docx) has sign here anchor tag /sn1/
    # document 3 (pdf)  has sign here anchor tag /sn1/
    #
    # The envelope has two recipients.
    # recipient 1 - signer
    # recipient 2 - cc
    # The envelope will be sent first to the signer.
    # After it is signed, a copy is sent to the cc person.

    # create the envelope definition
    env = EnvelopeDefinition(
        email_subject="Please sign this document set"
    )
    doc1_b64 = base64.b64encode(bytes(cls.create_document1(args), "utf-8")).decode("ascii")
    # read files 2 and 3 from a local directory
    # The reads could raise an exception if the file is not available!
    with open(path.join(demo_docs_path, doc_docx_path), "rb") as file:
        doc2_docx_bytes = file.read()
    doc2_b64 = base64.b64encode(doc2_docx_bytes).decode("ascii")
    with open(path.join(demo_docs_path, doc_pdf_path), "rb") as file:
        doc3_pdf_bytes = file.read()
    doc3_b64 = base64.b64encode(doc3_pdf_bytes).decode("ascii")

    # Create the document models
    document1 = Document(  # create the DocuSign document object
        document_base64=doc1_b64,
        name="Order acknowledgement",  # can be different from actual file name
        file_extension="html",  # many different document types are accepted
        document_id="1"  # a label used to reference the doc
    )
    document2 = Document(  # create the DocuSign document object
        document_base64=doc2_b64,
        name="Battle Plan",  # can be different from actual file name
        file_extension="docx",  # many different document types are accepted
        document_id="2"  # a label used to reference the doc
    )
    document3 = Document(  # create the DocuSign document object
        document_base64=doc3_b64,
        name="Lorem Ipsum",  # can be different from actual file name
        file_extension="pdf",  # many different document types are accepted
        document_id="3"  # a label used to reference the doc
    )
    # The order in the docs array determines the order in the envelope
    env.documents = [document1, document2, document3]

    # Create the signer recipient model
    signer1 = Signer(
        email=args["signer_email"],
        name=args["signer_name"],
        recipient_id="1",
        routing_order="1"
    )
    # routingOrder (lower means earlier) determines the order of deliveries
    # to the recipients. Parallel routing order is supported by using the
    # same integer as the order for two or more recipients.

    # create a cc recipient to receive a copy of the documents
    cc1 = CarbonCopy(
        email=args["cc_email"],
        name=args["cc_name"],
        recipient_id="2",
        routing_order="2"
    )

    # Create signHere fields (also known as tabs) on the documents,
    # We"re using anchor (autoPlace) positioning
    #
    # The DocuSign platform searches throughout your envelope"s
    # documents for matching anchor strings. So the
    # signHere2 tab will be used in both document 2 and 3 since they
    # use the same anchor string for their "signer 1" tabs.
    sign_here1 = SignHere(
        anchor_string="**signature_1**",
        anchor_units="pixels",
        anchor_y_offset="10",
        anchor_x_offset="20"
    )

    sign_here2 = SignHere(
        anchor_string="/sn1/",
        anchor_units="pixels",
        anchor_y_offset="10",
        anchor_x_offset="20"
    )

    # Add the tabs model (including the sign_here tabs) to the signer
    # The Tabs object wants arrays of the different field/tab types
    signer1.tabs = Tabs(sign_here_tabs=[sign_here1, sign_here2])

    # Add the recipients to the envelope object
    recipients = Recipients(signers=[signer1], carbon_copies=[cc1])
    env.recipients = recipients

    # Request that the envelope be sent by setting |status| to "sent".
    # To request that the envelope be created as a draft, set to "created"
    env.status = args["status"]

    return env

@classmethod
def create_document1(cls, args):
    """ Creates document 1 -- an html document"""

    return f"""
    <!DOCTYPE html>
    <html>
        <head>
          <meta charset="UTF-8">
        </head>
        <body style="font-family:sans-serif;margin-left:2em;">
        <h1 style="font-family: "Trebuchet MS", Helvetica, sans-serif;
            color: darkblue;margin-bottom: 0;">World Wide Corp</h1>
        <h2 style="font-family: "Trebuchet MS", Helvetica, sans-serif;
          margin-top: 0px;margin-bottom: 3.5em;font-size: 1em;
          color: darkblue;">Order Processing Division</h2>
        <h4>Ordered by {args["signer_name"]}</h4>
        <p style="margin-top:0em; margin-bottom:0em;">Email: {args["signer_email"]}</p>
        <p style="margin-top:0em; margin-bottom:0em;">Copy to: {args["cc_name"]}, {args["cc_email"]}</p>
        <p style="margin-top:3em;">
            Candy bonbon pastry jujubes lollipop wafer biscuit biscuit. Topping brownie sesame snaps sweet roll pie. 
            Croissant danish biscuit soufflé caramels jujubes jelly. Dragée danish caramels lemon drops dragée. 
            Gummi bears cupcake biscuit tiramisu sugar plum pastry. Dragée gummies applicake pudding liquorice. 
            Donut jujubes oat cake jelly-o. 
            Dessert bear claw chocolate cake gummies lollipop sugar plum ice cream gummies cheesecake.
        </p>
        <!-- Note the anchor tag for the signature field is in white. -->
        <h3 style="margin-top:3em;">Agreed: <span style="color:white;">**signature_1**/</span></h3>
        </body>
    </html>
    """

Step 3. Create and send the envelope

Next, you use the definition of the envelope that you created in the makeEnvelope method in Step 2 to create a new envelope and send it, adding your access token and base path to the request header.

When the envelope is sent, the documents inside it will be delivered to the email address you specified for signing. The API returns the ID and status of the new envelope.

  1. Python
envelope_args = args["envelope_args"]
# Create the envelope request object
envelope_definition = cls.make_envelope(envelope_args, doc_docx_path, doc_pdf_path)
api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"])
# Call Envelopes::create API method
# Exceptions will be caught by the calling function
envelopes_api = EnvelopesApi(api_client)
results = envelopes_api.create_envelope(account_id=args["account_id"], envelope_definition=envelope_definition)

envelope_id = results.envelope_id

return {"envelope_id": envelope_id}

Expected response

If you run this code example from our Quickstart or launcher projects, you should see a JSON response similar to the code shown.

In addition, the signer receives an email containing a signing link that they can use to open and electronically sign a document using the Docusign mobile app or the Docusign website. After signing is complete, the recipient receives a carbon copy (CC) of the email that includes all of the completed and signed documents.

{
  "envelopeId": "eead435f-xxxx-xxxx-xxxx-25b7d8523d2b",
  "uri": "/envelopes/eead435f-xxxx-xxxx-xxxx-25b7d8523d2b",
  "statusDateTime": "2020-08-18T23:36:26.8830000Z",
  "status": "sent"
}