# Sending Attachments

## Overview

Unifi supports sending attachments outbound in two ways:

1. **Streaming attachments**
2. **Embedding attachments in the message payload**

Both approaches use the **`AttachmentSender`** class to retrieve bonded attachments that are ready to be sent.

***

## Enable Attachment Sending

Attachment sending is configured per outbound message via **Message → Outbound → Attachments**.

This would typically be used with a message named "AddAttachment".

The following options control how and when attachments are sent:

#### Send Attachments

When **Send Attachments** is enabled, the message is marked as *attachment-capable*. This allows the message to access attachments through the `AttachmentSender` class during outbound processing, but does not by itself cause attachments to be sent.

#### Maximum Attachments to Send

The **Maximum attachments to send** setting limits the number of attachments that the message is permitted to send via `AttachmentSender`. This limit is enforced during outbound execution and applies regardless of whether attachments are streamed or embedded.

#### Attachment Added

When **Attachment added** is enabled, the message is triggered immediately when an attachment is added to the source record. In this mode, attachments are sent regardless of the message’s normal trigger conditions.

This allows attachments to be sent as soon as they are created, rather than waiting for a state change or other business event.

***

## AttachmentSender

`AttachmentSender` is responsible for iterating over **Bonded Attachments** associated with the current outbound transaction. It is typically used in the **Stage to Target** script of a message to fetch and selectively send attachments.

An `AttachmentSender` instance is created using the current transaction and bond:

```javascript
var sender = new x_snd_eb.AttachmentSender(transaction, bond);
```

Attachments are accessed sequentially using:

```javascript
sender.next();
```

Each call to `sender.next()` advances to the next eligible attachment, populates the sender with metadata for that attachment, and marks the associated **Bonded Attachment** record as **Sent**.

**Commonly Used Properties**

When an attachment is available, the following properties are exposed on the sender:

* `sender.attachment_id` — the `sys_id` of the attachment
* `sender.attachment_name` — the attachment file name
* `sender.attachment_type` — the attachment MIME type

**Attachment Selection**

The set of attachments exposed by `AttachmentSender` is automatically constrained by the integration’s attachment configuration, such as:

* Maximum attachment size
* Maximum number of attachments

Only attachments that meet these criteria are made available to the message.

**Accessing Attachment Content**

In addition to attachment metadata, `AttachmentSender` provides helper methods for accessing attachment content:

* **`getAttachmentContent()`**\
  Returns the attachment content as a string. This method only supports `.csv`, `.json`, and `.txt` files and returns up to **5 MB** of data.
* **`getAttachment()`**\
  Returns the current `sys_attachment` GlideRecord for the attachment being processed.

These methods are intended for scenarios where attachment content must be inspected or transformed before being sent, rather than streamed directly.

***

## Streaming Attachments

### Overview

Streaming attachments sends the attachment **as the outbound request payload**, rather than embedding it inside a structured message.

Key characteristics:

* **Exactly one attachment** may be streamed
* The attachment is streamed directly from ServiceNow
* The payload must be a `sys_attachment:<attachment_sys_id>` reference
* The `Content-Type` header must be set explicitly

Streaming is typically used when the **message itself represents the attachment**.

***

### Example Stage to Request Script (Streaming)

```javascript
(function processStageToRequest(request, stage, transaction, message, bond, scratchpad) {

  var sender = new x_snd_eb.AttachmentSender(transaction, bond);
  sender.next();

  var file_name = sender.attachment_name;
  var mime_type = sender.attachment_type;
  var attach_id = sender.attachment_id;
  var reference = bond.getValue('external_reference');

  //-----------------------
  // Path construction
  //-----------------------
  scratchpad.file_name = encodeURIComponent(file_name);
  scratchpad.reference = encodeURIComponent(reference);

  // Example endpoint: ?file_name=${scratchpad.file_name}&reference=${scratchpad.reference}

  //-----------------------
  // Headers construction
  //-----------------------
  scratchpad.headers = {
    "Content-Type": mime_type
  };

  //-----------------------
  // Payload construction
  //-----------------------
  // This string triggers attachment streaming outbound
  payload = 'sys_attachment:' + attach_id;

})(request, stage, transaction, message, bond, scratchpad);
```

***

### When to Use Streaming

Use streaming when:

* The outbound message **is the attachment**
* The target endpoint expects **raw binary data**
* Only one attachment is required

***

## Embedding Attachments

### Overview

Embedding attachments places attachment data **inside a structured payload**, such as JSON or XML.

Key characteristics:

* Supports **single or multiple attachments**
* Attachments are embedded inline
* Encoding is handled automatically
* Payload structure is fully controlled by the integration

Embedding supports multiple attachments, but iteration is only required when the target API explicitly supports or expects them.

***

### Attachment Data Placeholder

To embed attachment data, use the following placeholder tag in the payload template:

```xml
<x-attachment-data sys_id="sys_id"></x-attachment-data>
```

At runtime, Unifi replaces this tag with the **Base64-encoded attachment content** for the referenced attachment.

The placeholder is used to replace embedded attachment content so that attachment data does not need to be stored in request payloads, avoiding unnecessary load on the database and application server.

The `<x-attachment-data>` element can be self-closing (`<x-attachment-data ... />`), but in some instances an explicitly closed form (`<x-attachment-data ...></x-attachment-data>`) is required.

***

### Placement of `<x-attachment-data>`

The `<x-attachment-data>` tag is used **whenever attachments are embedded**, regardless of payload format.

What differs is **where the tag is defined**:

* **Message Templates**\
  The tag is placed in the **outbound template** and processed as part of template rendering.
* **Script-built payloads (for example JSON)**\
  The tag is added **directly to the payload object/string** in the *Stage to Request* script.

In both cases, Unifi replaces the tag at send time with the **Base64-encoded attachment content** for the referenced attachment.

***

### Example Stage to Request Script (Embedding)

```javascript
(function processStageToRequest(request, stage, transaction, message, bond, scratchpad) {

  var sender = new x_snd_eb.AttachmentSender(transaction, bond);
  scratchpad.attachments = [];

  while (sender.next()) {
    scratchpad.attachments.push({
      id: sender.attachment_id,
      name: encodeURIComponent(sender.attachment_name),
      mime: sender.attachment_type
    });
  }

})(request, stage, transaction, message, bond, scratchpad);
```

For single-attachment messages, this will typically result in one attachment entry.\
For multi-attachment messages, iteration is required and expected.

The number of attachments returned is automatically constrained by integration attachment configuration.

***

### Example Template (Embedding)

For integrations using the Message Template script, embedded attachments are typically represented as a single element where:

* The **file name** and **MIME type** are expressed as attributes
* The **Base64 content** is contained within the element body

This approach is commonly used for SOAP and other XML-based integrations, where the `<x-attachment-data>` tag is placed directly in the message template and processed during payload rendering.

```xml
<documents>
  <jelly:forEach var="att" items="${JS:scratchpad.attachments}">
    <document fileName="${HTML:att.name}" mimeType="${HTML:att.mime}">
      <x-attachment-data sys_id="${HTML:att.id}"></x-attachment-data>
    </document>
  </jelly:forEach>
</documents>
```

For integrations where the payload is constructed directly in the **Stage to Request** script (for example JSON-based REST APIs), the same `<x-attachment-data>` mechanism is used, but the tag is included in the script-generated payload instead of a template.

In all cases, Unifi replaces the `<x-attachment-data>` tag at send time with the **Base64-encoded attachment data** for the referenced attachment.

***

## Summary Comparison

| Feature               | Streaming             | Embedding                         |
| --------------------- | --------------------- | --------------------------------- |
| Attachments supported | One                   | One or many                       |
| Iteration required    | No                    | Only if message supports multiple |
| Payload type          | Raw binary            | Structured (JSON / XML)           |
| Trigger mechanism     | `sys_attachment:<id>` | `<x-attachment-data>`             |
| Encoding              | Native stream         | Base64                            |
| Typical use case      | File upload endpoints | Structured APIs                   |
