Examples

Add an attachment to an email

For this example, let’s assume we want to send out customer a quote for the new product they’ve ordered. The quote will be provided by our template system.

In order to render templates as PDF documents, PDF rendering must be setup.

workflow
Figure 1. The screenshot outlines the workflow that can be used to send an attachment via email.

The source code for the workflow example.

Workflow step details:
  1. (1) System; onManual:

    • resource: System

    • event: onManual

    • enabled: checked

  2. (2) Render quote:

    • type: Template render

    • arguments:

      • lookup:

        • type: Handle

        • value type: constant

        • value: quote

      • documentName:

        • value type: constant

        • value: quote

      • documentType:

        • value type: constant

        • value: application/pdf

      • options:

        • value type: constant

        • value: { "documentSize": "A4", "contentScale": "1", "orientation": "portrait", "margin": "0.3" }

    • results:

      • document target: quote

  3. (3) Render email:

    • type: Template render

    • arguments:

      • lookup:

        • type: Handle

        • value type: constant

        • value: content

      • documentType:

        • value type: constant

        • value: text/html

    • results:

      • document target: content

  4. (4) Build base email:

    • type: Email builder

    • arguments:

      • subject:

        • type: String

        • value type: constant

        • value: Quote for your product

      • to:

        • type: String

        • value type: constant

        • value: example@mail.tld

      • html:

        • type: Reader

        • value type: expression

        • value: content.document

    • results:

      • message target: email

  5. (5) Attach rendered template:

    • type: Email embedded attachment

    • arguments:

      • message:

        • type: EmailMessage

        • value type: expression

        • value: email

      • content:

        • type: Reader

        • value type: expression

        • value: quote.document

      • name:

        • type: String

        • value type: constant

        • value: quote.pdf

  6. (6) Send email:

    • type: Email sender

    • arguments:

      • message:

        • type: EmailMessage

        • value type: expression

        • value: email

  7. (7) Done

Make sure that the name parameter of the email embedded attachment uses a correct extension, such as .txt for plain text and .pdf for PDF. If the extension is omitted or incorrect, some email clients may display the attachment incorrectly or ignore it altogether.

The resulting email message includes the quote PDF as an attachment.

email mime contents
Figure 2. The screenshot outlines the raw received email message.

Example templates

The above example uses two templates: quote and content

template base content
Figure 3. The screenshot outlines the basic email content template used in the example.
The source code for the email content template:
<!DOCTYPE html>
<html>
<head>
  <meta charset='utf-8'>
  <meta http-equiv='X-UA-Compatible' content='IE=edge'>
  <title>Quote for our services</title>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
</head>
<body>
  <h1>Hello!</h1>
  <p>
    Attached is the quote for our services.
  </p>
  <p>
    Best, Team ltd
  </p>
</body>
</html>
template base quote
Figure 4. The screenshot outlines the basic quote template used in the example.
The source code for the quote template:
<!DOCTYPE html>
<html>
<head>
  <meta charset='utf-8'>
  <meta http-equiv='X-UA-Compatible' content='IE=edge'>
  <title>Quote#012356</title>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
</head>
<body>
  <h1>Quote#012356</h1>
  <p>
    Service quote for our services
  </p>
</body>
</html>

Parse Integration Gateway Request

Fort this example, let’s parse a request sent to the Integration Gateway

parse gateway payload
Figure 5. The screenshot outlines the workflow that can be used to process the request.

The source code for the workflow example.

Workflow step details:
  1. (1) System; onManual:

    • resource: System

    • event: onManual

    • enabled: checked

  2. (2) Parse request payload:

    • type: Process arbitrary data in jsenv

    • arguments:

      • scope:

        • type: Any

        • value type: expression

        • value: payload

      • source: refer below

    • results:

      • resultAny: parsedPayload

  3. (3) Debug state

  4. (7) Done

Integration gateway configuration

Table 1. Below are the configuration parameters for the corresponding integration gateway:

Endpoint

/examples/payload

Prefilter

Header: Token == "SOME_SECRET_TOKEN"

Processing

Workflow processer: On request payload notify user

Postfilter

Default JSON Response

cURL request

Below is an example of the cURL request that invokes the integration gateway and workflow:
curl -X POST "$CORTEZA_BASE/api/gateway/examples/payload" \
  -H "Content-Type: application/json" \
  -H 'Token: SOME_SECRET_TOKEN' \
  -d '{"name":"Peter","id":123}';

JSEnv parsing function

Below is the extracted source code which should be used in the JSEnv function step:
var inputData;

try {
    inputData = JSON.parse(input)
} catch (e) {
    throw new Error('could not parse input payload: ' + e);
}

if (!inputData.name) {
    throw new Error('could not parse input payload, name missing');
}

return {
    id: inputData.id,
    name: inputData.name
}

Interval

For this example, let’s assume we want to send an email to all users every Christmas at midnight. For this, we use a trigger of type onInterval with the interval 0 0 25 12 *

workflow example interval

Workflow step details:
  1. (1) Test trigger:

    • resource: System

    • event: onInterval

    • enabled: checked

    • constraints:

      • interval: 0 0 25 12 *

  2. (2) Iterate over Users:

    • type: Users

    • results:

      • user target: user

  3. (3) Send Email:

    • type: Email

    • arguments:

      • subject:

        • value type: constant

        • value: Merry christmas

      • to:

        • value type: expression

        • value: user.email

      • plain:

        • value type: constant

        • value: Merry christmas

  4. (4) Done:

Template rendering

In this example, we’ll take a look at how to render different templates that were made in our template system.

To start, create a template of type HTML in our templating system located in the admin area.

Rendering an HTML template

Create a workflow similar to the one below.

Make sure to look at the step details of steps (2) and (3).

html workflow
Figure 6. The screenshot outlines the workflow that renders an HTML template and sends it as an email.

The source code for the workflow can be found here.

Workflow step details:
  1. (1) System; onManual:

    • resource: System

    • event: onManual

    • enabled: checked

  2. (2) Render template:

    • type: Template render

    • arguments:

      • lookup:

        • type: Handle

        • value type: constant

        • value: email-template

      • documentName:

        • value type: constant

        • value: Email template

      • documentType:

        • value type: constant

        • value: text/html

    • results:

      • document target: renderedTemplate

  3. (3) Send email:

    • type: Email

    • arguments:

      • subject:

        • type: String

        • value type: constant

        • value: Email template

      • from:

        • type: String

        • value type: constant

        • value: demo@mail.com

      • to:

        • type: String

        • value type: constant

        • value: test@mail.com

      • html:

        • type: Reader

        • value type: expression

        • value: renderedTemplate.document

    • results:

      • document target: content

Make sure that the documentType parameter of the (2) Render template is of value text/html.

Rendering a PDF template

The difference between HTML and PDF rendering is that the documentType parameter changes to application/pdf.

With PDFs you can also adjust the render options to modify how the final PDF is rendered.

In order to render templates as PDF documents, you need to setup PDF rendering.

pdf workflow
Figure 7. The screenshot outlines the workflow that renders a PDF template and sends it as an email attachment.

The source code for the workflow can be found here.

Workflow step details:
  1. (1) System; onManual:

    • resource: System

    • event: onManual

    • enabled: checked

  2. (2) Render template:

    • type: Template render

    • arguments:

      • lookup:

        • type: Handle

        • value type: constant

        • value: pdf-template

      • documentName:

        • value type: constant

        • value: PDF template

      • documentType:

        • value type: constant

        • value: application/pdf

      • options:

        • type: renderOptions

        • value type: expression

        • value: { "documentSize": "A4", "contentScale": "1", "orientation": "portrait", "margin": "0.3" }

    • results:

      • document target: renderedTemplate

  3. (3) Build email:

    • type: Email builder

    • arguments:

      • subject:

        • type: String

        • value type: constant

        • value: PDF template

      • from:

        • type: String

        • value type: constant

        • value: test@mail.com

      • to:

        • type: String

        • value type: constant

        • value: example@mail.com

      • html:

        • type: Reader

        • value type: expression

        • value: content.document

    • results:

      • message target: email

  4. (4) Attach PDF template:

    • type: Attach PDF template

    • arguments:

      • message:

        • type: EmailMessage

        • value type: expression

        • value: email

      • content:

        • type: Reader

        • value type: expression

        • value: renderedTemplate.document

      • name:

        • type: String

        • value type: constant

        • value: PDF template.pdf

  5. (5) Send email:

    • type: Email sender

    • arguments:

      • message:

        • type: EmailMessage

        • value type: expression

        • value: email

You can combine both types of templates to render dynamic emails with PDF attachments.

The example for the workflow can be found here

Timestamp

For this example, let’s assume we want to wish all users a Happy new year. All the emails need to be sent out at exactly midnight. For this, we use a trigger of type onTimestamp with the timestamp of 2021-01-01T00:00:00Z

workflow example timestamp

Workflow step details:
  1. (1) Test trigger:

    • resource: System

    • event: onTimestamp

    • enabled: checked

    • constraints:

      • timestamp: 2021-01-01T00:00:00Z

  2. (2) Iterate over Users:

    • type: Users

    • results:

      • user target: user

  3. (3) Send Email:

    • type: Email

    • arguments:

      • subject:

        • value type: constant

        • value: Happy new year

      • to:

        • value type: expression

        • value: user.email

      • plain:

        • value type: constant

        • value: Happy new year

  4. (4) Done:

Workfing with Records

The section outlines some tips and tricks you can use when working with records.

Checking for existence

In case where you wish to perform some task depending on the existence of records, you can use either of the following approaches.

Both approaches are valid and there is no benefit between using one or the other. Decide based on your preferences/context.

Approach A

When searching for records, tick the incTotal option and assign the total result value to a variable.

Inside the gateway, check if the total value is greater then 0.

The screenshot outlines a basic example of checking for existence.
Figure 8. The screenshot outlines a basic example of checking for existence.

You can find the source code for the workflow here.

Approach B

Inside the gateway, check if the count(items) value is greater then 0.

The screenshot outlines a basic example of checking for existence.
Figure 9. The screenshot outlines a basic example of checking for existence.

You can find the source code for the workflow here.

Create or update

When creating the record you need to call the compose record create function, and when updating the record, you need to call the compose record update function.

Only the highlighted portion performs the create/update check; the rest is boilerplate to get it to the desired state.

If you need to call one or the other on-the-fyly, you can use the following approach. You can use the record.recordID != "0" to determine if the record needs to be updated — the default recordID value is "0".

The screenshot outlines a basic example of checking for existence.
Figure 10. The screenshot outlines a basic example of checking for existence.

You can find the source code for the workflow here.

Removing the value

To remove some record value, use an expression step to set the value in question to an empty Any.

The screenshot outlines a basic example of removing record values.
Figure 11. The screenshot outlines a basic example of removing record values.

You can find the source code for the workflow here.

Handling missing values

To use the default value in case the record value does not exist, you need to use the ?? operator.

To exemplify, using a ?? b will return a if it exists or b if it does not.

The below example uses a variable as the default value. You can use a constant such as "something string" or 42.

The screenshot outlines a basic example of using default values.
Figure 12. The screenshot outlines a basic example of using default values.

You can find the source code for the workflow here.

Parallelism

This section provides some examples on how you should perform tasks in parallel.

Unconditional parallelism

Unconditional parallelism should be used when two or more branches of execution should be done in parallel regardless of the state.

To achieve this, use the fork gateway gatewayParallel where each outbound branch defines one branch of parallel execution.

If any of the branches defines the termination step termination, the entire workflow will be terminated.

The screenshot outlines a basic example of unconditional parallel execution.
Figure 13. The screenshot outlines a basic example of unconditional parallel execution.

You can find the source code for the workflow here.

Unconditional parallel segment

A parallel segment is where the workflow transitions from sequential execution into parallel execution and back into sequential execution.

Unconditional parallelism should be used when two or more branches of execution should be done in parallel regardless of the state.

To achieve this, use the fork gateway gatewayParallel where each outbound branch defines one branch of parallel execution. Terminate the parallel segment by using the join gateway gatewayParallel.

If any of the branches defines the termination step termination, the entire workflow will be terminated.

The screenshot outlines a basic example of unconditional parallel execution.
Figure 14. The screenshot outlines a basic example of unconditional parallel execution.

You can find the source code for the workflow here.

Conditional parallelism

conditional parallelism should be used when two or more branches of execution should be done in parallel regardless of the state.

To achieve this, use the fork gateway gatewayParallel where each outbound branch defines one branch of parallel execution.

If any of the branches defines the termination step termination, the entire workflow will be terminated.

The screenshot outlines a basic example of conditional parallel execution.
Figure 15. The screenshot outlines a basic example of conditional parallel execution.

You can find the source code for the workflow here.

Conditional parallel segment

A parallel segment is where the workflow transitions from sequential execution into parallel execution and back into sequential execution.

conditional parallelism should be used when two or more branches of execution should be done in parallel regardless of the state.

To achieve this, use the fork gateway gatewayParallel where each outbound branch defines one branch of parallel execution. Terminate the parallel segment by using the join gateway gatewayParallel.

If any of the branches defines the termination step termination, the entire workflow will be terminated.

The screenshot outlines a basic example of conditional parallel execution.
Figure 16. The screenshot outlines a basic example of conditional parallel execution.

You can find the source code for the workflow here.

Dynamic Configuration

When defining automation which needs to interact with external systems or you need to make the workflow execution configurable, static workflows may prove challenging to use.

You can define a settings module where you can define all of the configurable parameters your automation requires. This can be anything from URL addresses to login credentials and access tokens.

When storing access tokens and other credentials, make sure to properly configure access control.

The screenshot outlines a basic example of the `settings` module.
Figure 17. The screenshot outlines a basic example of the settings module.

Inside your workflow, simply fetch the record from the settings module and configure your execution using it’s values.

The screenshot outlines a basic example of a workflow that utilizes the `settings` module.
Figure 18. The screenshot outlines a basic example of a workflow that utilizes the settings module.

You can find the source code for the workflow here.

Execution timeout

Corteza workflows' execution does not timeout by default (the workflow can run indefinitely).

If your use-case requires you to define a timeout, you can implement this manually.

The below example does two things:
  • Schedule a timeout after 10sec of execution,

  • repeat the iterator indefinitely.

manual timeout
Workflow step details:
  1. (1) Test trigger:

    • resource: System

    • event: onManual

    • enabled: checked

  2. (2) Fork:

    • gateway: Inclusive

    • conditions:

      • true

      • true

  3. (3) Wait 10sec:

    • offset: 10

  4. (4) Log context timeout:

    • type: Log debug message

    • arguments:

      • message:

        • value type: constant

        • value: Context timeout

  5. (5) Context timeout: /

  6. (6) Repeat indefinitely:

    • type: Condition

    • arguments:

      • while:

        • value type: expression

        • value: true

  7. (7) Log iteration:

    • type: Log debug message

    • arguments:

      • message:

        • value type: constant

        • value: Iterator loop

  8. (8) Done: /

  9. (9) Completed: /