---
title: "Attach a metafield file (invoice PDF) to a Shopify Flow email"
description: "Send the PDF another app saved on an order or customer metafield as an email attachment from Shopify Flow: setup, permissions, file names, empty metafields and limits."
canonical: "https://docs.workflow-transactional-email.app/attachments-from-metafields"
---

# Attach a file from an order or customer metafield

> [!NOTE]
> **Coming soon**
> This feature ships with version 1.17. The page is here so you can plan for it; the **Metafield** option appears in the layout editor as soon as the release is out.

Many apps save a file on the order or the customer: an invoice or packing slip PDF from an invoicing app, a certificate, a signed contract. Shopify stores it in a metafield, either as a **file** in your Shopify Files or as a **link** to the file. This app can attach that file to the email a Flow workflow sends, without you uploading or linking anything by hand.

## How it works

1. Another app (or you) writes the file, or a link to it, into a metafield of the order or customer. In your Shopify admin that is **Settings > Custom data > Orders** (or **Customers**): a definition of type **File**, **URL**, or a text field an app writes a link into.
2. In an email layout you add an attachment and choose **Metafield** as its source, then pick that definition. The picker shows what each one holds: a file, a link, or a list of either.
3. In Shopify Flow, the **Send Transactional Email** or **Send Marketing Email** step has an **Order** field and a **Customer** field. Flow fills them from the trigger, so a workflow started by *Order created* already knows which order.
4. When the email is sent, the app reads that metafield on that order or customer, downloads the file (from your Shopify Files, or from the link), and attaches it. A **list** metafield attaches every entry.

The layout only names the metafield. The workflow says whose order or customer, so one layout serves every order.

### Files and links

| The metafield holds | Definition type | What the app does |
| --- | --- | --- |
| A Shopify file | File, List of files | Follows the reference to the file in your Files and downloads it |
| A link | URL, List of URLs, or a text field | Downloads the file from that link. Only `https://` links work; a link that does not answer or points at something other than a PDF, image, CSV or text file fails the send with the reason |

Either way the size is checked when the email is sent, not in the editor, so metafield attachments are not counted in the editor's attachment total.

## Set it up

### Rich text and HTML layouts

In the **Attachments** card at the bottom of the editor, click **Add from metafield**. Pick **Order** or **Customer**, then the definition. The row shows the definition's name, what it holds and its `namespace.key`; **Change** picks another one.

### Visual layouts

Add an **Attachment** block (or open one) and switch its source to **Metafield**. **Choose metafield** opens the same picker.

### The permission

The app is installed without any access to your store data. The first time you pick an order or customer metafield, the picker asks for permission to read that resource's metafields and the files they point to. Shopify shows its own consent dialog; after **Update**, the list of definitions loads.

You can review and withdraw every permission at any time on the app's **Permissions** page. Withdrawing one makes every email that attaches a file from such a metafield fail until it is granted again. What each permission reads, and what it does not, is on [Permissions: what the app can read from your store](https://docs.workflow-transactional-email.app/permissions.md).

> [!TIP]
> **What the app reads**
> Only the one metafield named in the layout, on the one order or customer the Flow step is about, plus the file it points to. Nothing else on the order or customer is read, and nothing is stored: the file is downloaded when the email is sent and attached to that email.

## File name

By default the attachment keeps the file's own name: the name in your Shopify Files, or the last part of the link. The **File name** field overrides it and supports Liquid, for example `invoice-{{ variables.order_name }}.pdf`. When a list metafield holds several entries, the second and following get `-2`, `-3` appended to the override.

## When the metafield is empty

The app that writes the file often runs a few seconds after the trigger, so at the moment the email step runs the metafield can still be empty. What happens then depends on the **Optional** checkbox of the attachment:

| Optional | Behaviour |
| --- | --- |
| Off (default) | The email is not sent yet. The app tells Flow to retry the step, and Flow redelivers it a little later; the email goes out as soon as the file is there. |
| On | The email is sent without this attachment. |

Leave it off for an invoice that must be there. Turn it on for a file that only some orders have.

## Requirements and limits

- The Flow step needs its **Order** or **Customer** field set. Steps that were added before this release do not have the fields yet: delete the step in the Flow editor and add it again.
- Files up to **10 MB** each; PDF, images, CSV, plain text and calendar files. Videos and 3D models are skipped.
- Links must start with `https://` and answer without a login. A link that redirects to a non-https address, or into a private network, is refused.
- **Orders of the last 60 days.** Shopify only lets apps read recent orders. For a workflow on an older order the send fails with a clear message.
- Microsoft 365 rejects messages with more than 4 MB of attachments in total; see [Attachments and images](https://docs.workflow-transactional-email.app/attachments-and-images.md).

## What you see in History

Every outcome is on the History page. A step without an order, a withdrawn permission, an order Shopify cannot find, a link that does not answer, or a file over the limit is recorded as **Failed** with the reason and what to change. An empty metafield with **Optional** off is not a failure: Flow shows the retries, and the send appears once the file is there. A **Resend** from History reads the same order or customer again.

## Test it

**Send test email** in the layout editor has no order or customer to read from, so it sends without metafield attachments. To test the attachment, run the workflow in Flow on an order that already has the file, or use **Run** on a Flow test with such an order.

## Related

- [Permissions: what the app can read from your store](https://docs.workflow-transactional-email.app/permissions.md) - what the optional permissions read, and how to withdraw them.
- [Attachments and images](https://docs.workflow-transactional-email.app/attachments-and-images.md) - uploaded attachments, Attach vs Link mode and sizes.
- [Passing data from Shopify Flow](https://docs.workflow-transactional-email.app/passing-data-from-shopify-flow.md) - the step fields and variables.
- [History and troubleshooting](https://docs.workflow-transactional-email.app/history-and-troubleshooting.md) - reading a failed send.
