Custom Pipeline Email Notifications

Tetra Data Pipelines can send email notifications when a workflow completes or fails. With custom templates enabled, you can replace the default email body with your own HTML content using Handlebars syntax ({{variable}}).

Custom templates are configured for each pipeline in the Pipeline Editor under the Notifications section. For instructions, see Create Custom Pipeline Email Notifications.

You can define separate body and subject templates for success and failure notifications. All templates use the same Handlebars variables.

📘

NOTE

Custom pipeline email notifications are available in TDP v4.4.2 and higher as part of a limited availability release and must be activated in coordination with TetraScience. To start using custom notifications, contact your customer account leader.

Pipeline Success Custom Email Notification Template

<h2>Workflow Completed Successfully</h2>

<p><strong>Organization:</strong> {{org}}</p>
<p><strong>Pipeline:</strong> <a href="{{workflow.pipeline.url}}">{{workflow.pipeline.name}}</a></p>
<p><strong>Workflow ID:</strong> {{workflow.id}}</p>
<p><a href="{{workflow.url}}">View Workflow Details →</a></p>
{{#if workflow.trigger.file.name}}
  <p><strong>File Processed:</strong> {{workflow.trigger.file.name}}</p>
{{/if}}

{{#if workflow.trigger.file.labels}}
  <h3>File Labels</h3>
  <ul>
  {{#each workflow.trigger.file.labels}}
    <li><strong>{{@key}}:</strong> {{this}}</li>
  {{/each}}
  </ul>
{{/if}}

Pipeline Failure Custom Email Notification Template

<h2>Workflow Failed</h2>

<p><strong>Organization:</strong> {{org}}</p>
<p><strong>Pipeline:</strong> <a href="{{workflow.pipeline.url}}">{{workflow.pipeline.name}}</a></p>
<p><strong>Workflow ID:</strong> {{workflow.id}}</p>
{{#if workflow.trigger.file.name}}
  <p><strong>File:</strong> {{workflow.trigger.file.name}}</p>
{{/if}}

{{#if workflow.error}}
  <h3>Error</h3>
  <pre style="background: #f5f5f5; padding: 10px; overflow-x: auto;">{{workflow.error}}</pre>
{{/if}}

{{#each workflow.tasks}}
  {{#if this.isFailed}}
    <h3>Failed Task: {{this.step}}</h3>
    {{#if this.error}}
      <p><strong>Error:</strong> {{this.error}}</p>
    {{/if}}
  {{/if}}
{{/each}}

{{#if workflow.trigger.file.labels}}
  <h3>File Labels</h3>
  <ul>
  {{#each workflow.trigger.file.labels}}
    <li><strong>{{@key}}:</strong> {{this}}</li>
  {{/each}}
  </ul>
{{/if}}

<p><a href="{{workflow.url}}">View Workflow Details →</a></p>

🚧

IMPORTANT

Deprecated fields: workflow.logs (v2 protocol-only, rarely populated) and task[*].output (not yet supported) are documented for completeness but not recommended for use. Use workflow.error and task[*].error instead.

Important Considerations

  • Subject lines: Custom subject templates use the same Handlebars variables as the body. Subjects are rendered as plain text only. any HTML tags are automatically stripped. If no custom subject is defined, the platform generates a default.
  • Sender and recipients: Sender address and recipient list are controlled by pipeline notification settings in the TDP UI, not the template.
  • Fallback behavior: If a custom template fails to compile (syntax error), the email will fall back to the default TDP template.
  • Inline styles only: Email clients (Gmail, Outlook, Apple Mail) strip <style> blocks and ignore external stylesheets. All CSS must be applied as inline style attributes — e.g., <pre style="background: #f5f5f5; padding: 10px;">. The examples in this document follow this pattern.
  • Available helpers: Only built-in Handlebars helpers are available: #if, #each, #with, lookup. Custom helpers like json, stringify, etc. are not registered and will cause template compilation to fail silently.

Available Template Variables

The following variables are available inside your Handlebars templates at render time, organized by context:

Root-Level Variables

VariableTypeDescription
environmentstringDeployment name and environment (e.g., "prod - prod")
domainstringPlatform domain (e.g., "tetrascience.com")
orgstringOrganization slug (e.g., "my-org")

Workflow Context (workflow.*)

VariableTypeDescription
workflow.idstringUnique workflow execution ID
workflow.statusstring"completed" or "failed"
workflow.isSuccessbooleantrue if workflow completed successfully
workflow.isFailedbooleantrue if workflow failed
workflow.errorstringError message (if failed)
workflow.urlstringDirect URL to view workflow details in TDP
workflow.logsarrayDeprecated. Array of log entries (v2 protocols only, rarely populated). Not recommended for use.

Pipeline Context (workflow.pipeline.*)

VariableTypeDescription
workflow.pipeline.idstringPipeline ID
workflow.pipeline.namestringPipeline name as configured in TDP
workflow.pipeline.urlstringDirect URL to edit the pipeline in TDP
workflow.pipeline.revisionnumberPipeline configuration revision number
workflow.pipeline.artifact.namespacestringProtocol namespace (e.g., "common")
workflow.pipeline.artifact.slugstringProtocol slug (e.g., "python-exec-benchling")
workflow.pipeline.artifact.versionstringProtocol version (e.g., "v1.0.0")
workflow.pipeline.artifact.typestringArtifact type (e.g., "protocol")

File/Trigger Context (workflow.trigger.file.*)

VariableTypeDescription
workflow.trigger.fileobjectPresent for file-triggered workflows. May be absent for other trigger types — guard with {{#if workflow.trigger.file}}
workflow.trigger.file.namestringFilename that triggered the workflow, or "scheduled" for scheduled pipelines
workflow.trigger.file.metadataobjectCustom metadata tags from the file (object, not JSON string—use dot notation: {{workflow.trigger.file.metadata.project}})
workflow.trigger.file.tagsarrayArray of custom tags
workflow.trigger.file.labelsobjectObject mapping label names to label values (like {"sample_id": "S0123", "instrument": "INST-00501"})

🚧

IMPORTANT

Labels are a flat object, not an array of objects with 'name', 'value' properties
To iterate over labels, use the handlebars #each keyword. For example:
{{#each workflow.trigger.file.labels}}
{{@key}}: {{this}}
{{/each}}

Task Context (workflow.tasks.*)

VariableTypeDescription
workflow.tasksarrayArray of task execution objects
workflow.tasks[*].idstringTask ID
workflow.tasks[*].stepstringTask script slug/name
workflow.tasks[*].statusstringTask status: "completed", "failed", "skipped", etc.
workflow.tasks[*].isSuccessbooleantrue if task completed successfully
workflow.tasks[*].isFailedbooleantrue if task failed
workflow.tasks[*].isSkippedbooleantrue if task was skipped
workflow.tasks[*].inputobjectTask input data
workflow.tasks[*].outputobjectPlaceholder field. Almost always empty ({}).
workflow.tasks[*].erroranyError details if the task failed. Shape varies by task type and failure mode. Use the debug blocks to inspect the actual structure for your pipeline
workflow.tasks[*].script.namespacestringScript namespace
workflow.tasks[*].script.slugstringScript slug
workflow.tasks[*].script.versionstringScript version
workflow.tasks[*].script.functionstringFunction name
workflow.tasks[*].memoryInMBnumberMemory allocated to task
workflow.tasks[*].eventsarrayArray of task lifecycle events with status and at (timestamp)

Custom Subject Lines

Custom subject templates use the same Handlebars variables as body templates. Subjects are rendered as plain text only. Any HTML tags are automatically stripped.

Example Success Subject

[{{org}}] {{workflow.pipeline.name}} — {{workflow.trigger.file.name}}

Example Failure Subject

[{{org}}] {{workflow.pipeline.name}} failed — {{workflow.error}}

If no custom subject is defined, the platform generates a default:

  • Success: [org] Workflow Successful - protocol-slug
  • Failure: [org] Workflow Failed - protocol-slug

Debugging Your Template

If your template isn't rendering as expected, you can inspect the actual data structure by adding debug blocks to your template. The Handlebars renderer automatically converts all objects to JSON.

Debug Blocks

Add these sections anywhere in your template to inspect the data:

<!-- Debug: Print the entire workflow object -->
<div style="background: #f5f5f5; padding: 10px; margin: 20px 0; border: 2px solid red;">
  <h3>DEBUG: Full Workflow Context</h3>
  <pre style="overflow: auto; font-size: 11px; white-space: pre-wrap;">{{workflow}}</pre>
</div>

<!-- Debug: Print file/trigger data -->
<div style="background: #f5f5f5; padding: 10px; margin: 20px 0; border: 2px solid red;">
  <h3>DEBUG: File/Trigger Data</h3>
  <pre style="overflow: auto; font-size: 11px; white-space: pre-wrap;">{{workflow.trigger.file}}</pre>
</div>

<!-- Debug: Print labels specifically -->
<div style="background: #f5f5f5; padding: 10px; margin: 20px 0; border: 2px solid red;">
  <h3>DEBUG: File Labels</h3>
  <pre style="overflow: auto; font-size: 11px; white-space: pre-wrap;">{{workflow.trigger.file.labels}}</pre>
</div>

<!-- Debug: Print all tasks -->
<div style="background: #f5f5f5; padding: 10px; margin: 20px 0; border: 2px solid red;">
  <h3>DEBUG: All Tasks</h3>
  <pre style="overflow: auto; font-size: 11px; white-space: pre-wrap;">{{workflow.tasks}}</pre>
</div>

When your template is rendered and sent, these debug sections will display the actual JSON structure of the data, showing you exactly what properties are available. This is especially useful in the following situations:

  • Variables are rendering as empty or undefined
  • You're unsure about the structure of nested objects
  • You want to verify that data is being passed to the template

Remember to remove these debug blocks before putting your template into production!

Documentation Feedback

Do you have questions about our documentation or suggestions for how we can improve it? Start a discussion in TetraConnect Hub. For access, see Access the TetraConnect Hub.

📘

NOTE

Feedback isn't part of the official TetraScience product documentation. TetraScience doesn't warrant or make any guarantees about the feedback provided, including its accuracy, relevance, or reliability. All feedback is subject to the terms set forth in the TetraConnect Hub Community Guidelines.