Get Plugin

Email Attachments

Email Attachments

Easy PDF Invoices for WooCommerce attaches the right document to the right WooCommerce email automatically. This page covers how attachment works, which emails are included by default, and how to control attachment behaviour per email type.

Default behaviour

Out of the box, the plugin attaches:

WooCommerce emailDocument attached
Customer Processing OrderInvoice
Customer Completed OrderReceipt
Customer Refunded OrderCredit Note
Customer Partially Refunded OrderCredit Note
New Order (admin)Invoice
Scroll to see all columns →
You can disable any of these per email from WooCommerce > Settings > Invoices > Emails.

Per-email toggles

The Emails tab has one toggle for each WooCommerce email:

  • Attach to Customer Processing Order (default: on)
  • Attach to Customer Completed Order (default: on)
  • Attach to Customer Refunded Order (default: on)
  • Attach to Customer Partially Refunded Order (default: on)
  • Attach to Customer Invoice / Order Details (default: off)
  • Attach to New Order admin email (default: on)
Toggling off means the PDF is neither generated for that email nor attached. If the customer later downloads from My Account, the PDF is generated lazily at that moment.

Attachment method

Three options control how the PDF gets to the customer:

Attachment only (default)

PDF is attached to the email. No download link in the body.

Use when:

  • Most of your customers read email on desktop or tablets where attachments work reliably.
  • You want a single canonical source of truth — the attached file.

Download link only

No attachment. A "Download your invoice" link is inserted into the email body.

Use when:

  • You're worried about email size limits (large PDFs trigger spam filters or get truncated).
  • You want analytics on link clicks.
  • You serve high-volume stores where attachment generation per email is overhead you'd rather avoid.
The link points to a secure download URL that uses the order key for guest authentication.

Both

Attachment + download link in the body. Belt and braces.

None

Neither. The PDF still gets generated lazily when the customer downloads from My Account or admin clicks Download.

When the attachment method is link or both, you control where in the email the link appears:

  • Before order table — link sits at the top of the email body, above the order summary.
  • After order table — link sits at the bottom, below the order summary.
The link inherits WooCommerce's email styling so it looks native. Plain-text emails get a plain-text version of the link.

Lazy generation

The plugin only generates a PDF when it's actually needed:

  • A customer email is being sent → generate now if missing, attach.
  • A customer downloads from My Account → generate now if missing, stream.
  • Admin clicks Regenerate → always regenerate, replacing the previous file.
This avoids burning CPU on PDFs that may never be opened. A typical 5-item order PDF takes under 500ms to generate, so the latency added to email sending is negligible.

Order status changes and email attachments

When an order moves between statuses, the plugin's StatusListener decides whether to regenerate the PDF before the next email goes out:

  • Processing → Completed. Invoice (unpaid) becomes Receipt (paid). The PDF is regenerated so the customer's Completed email gets the right document with the PAID badge.
  • Completed → Refunded. Receipt becomes Credit Note. The Customer Refunded email gets the credit note.
  • Processing → Cancelled / Failed. No regeneration. No email attachment for those statuses.

Customer email IDs reference

The plugin hooks into woocommerce_email_attachments and matches against these WooCommerce email IDs:

Email IDRecipientDefault toggle
customer_processing_orderCustomerOn
customer_completed_orderCustomerOn
customer_refunded_orderCustomerOn
customer_partially_refunded_orderCustomerOn
customer_invoiceCustomerOff
customer_noteCustomerOff
new_orderAdminOn
cancelled_orderAdminOff
failed_orderAdminOff
Scroll to see all columns →
WooCommerce also fires custom email IDs for plugins like WooCommerce Subscriptions. The plugin's email matcher uses the email ID as a key in epdi_settings['emails'], so any WooCommerce email type can be controlled — even if it's not in the default UI.

Filtering attachment behaviour

For surgical control, use the epdi_attach_to_email filter:

// Disable attachment for orders over $1000 (link only instead)
add_filter( 'epdi_attach_to_email', function( $should_attach, $email_id, $order ) {
    if ( $order->get_total() > 1000 ) {
        return false;
    }
    return $should_attach;
}, 10, 3 );

// Force attachment to a custom email type from another plugin
add_filter( 'epdi_attach_to_email', function( $should_attach, $email_id, $order ) {
    if ( $email_id === 'wcs_renewal_order' ) {
        return true;
    }
    return $should_attach;
}, 10, 3 );

Use epdi_before_email_attach for actions that need to run just before the file is added to the attachment list:

add_action( 'epdi_before_email_attach', function( $order, $email_id ) {
    error_log( "Attaching PDF for order {$order->get_id()} to {$email_id}" );
}, 10, 2 );

Custom email types

If you have a custom email plugin that fires woocommerce_email_attachments with a custom email ID, the plugin handles it automatically — it just needs the email's setting key to be present in epdi_settings['emails'].

You can register custom email IDs through the epdi_attachable_email_ids filter so they appear in the settings UI:

add_filter( 'epdi_attachable_email_ids', function( $ids ) {
    $ids['wcs_renewal_order'] = 'WooCommerce Subscriptions Renewal';
    return $ids;
} );

After this, the Emails tab shows a toggle for "Attach to WooCommerce Subscriptions Renewal".

Troubleshooting

"The customer email arrived but the PDF didn't"

Check, in order:

  • Is the toggle on? Go to Settings > Invoices > Emails and confirm the email type is enabled.
  • Did the PDF generate? Open the order edit screen. The Easy PDF Invoices metabox should show a generated invoice number and file size. If it doesn't, click Regenerate.
  • Is the WooCommerce email enabled? Go to WooCommerce > Settings > Emails and confirm the relevant email is enabled. The plugin can't attach to an email that WooCommerce isn't sending.
  • Are you on a host that strips attachments? Some shared hosts block emails with attachments above a certain size. Switch the attachment method to link and check whether the email lands.

"The link in the email doesn't work for guest customers"

Guest download links use the order key as authentication (?epdi_download={order_id}&key={order_key}). If the link doesn't work, check:

  • Did the customer click the right link? Some email clients rewrite URLs. The plugin uses raw <a href> tags to minimise rewrites.
  • Did the order key change? WooCommerce regenerates order keys in some edge cases (refunds, custom plugins). The link sent in the email uses the key at the time of sending.
  • Is rate limiting blocking? The download endpoint allows 10 downloads per minute per identity. A customer trying to download repeatedly may hit the limit and see a 429 with a Retry-After: 60 header.

"I want different documents on different emails"

By default the plugin maps emails to documents via the resolution rules in Document Types. To force a specific document for a specific email, use the epdi_email_document_type filter:

add_filter( 'epdi_email_document_type', function( $type, $email_id, $order ) {
    if ( $email_id === 'customer_completed_order' ) {
        return 'receipt'; // Force receipt even if the order isn't paid
    }
    return $type;
}, 10, 3 );