Skip to Content
EmailsWooCommerce

How to Customize WooCommerce Emails in 2026 – Settings, Block Editor, Templates and Hooks

How to Customize WooCommerce Emails in 2026 – Settings, Block Editor, Templates and Hooks

This guide is for store owners and developers who want to customize WooCommerce emails without breaking them on the next update. I build and maintain WooCommerce stores for clients in the US, the UK and EU, and Australia, and the questions are always the same: how do I change the text, where do template files go, which hook do I use, and why is the order email going to spam?

Last verified: October 2026, against WooCommerce 11.2 and the official WooCommerce documentation.

I cover the options in order of effort, then translation, testing, deliverability and regional rules. Pick the lowest level that does the job, because every level above it is more code to maintain.

Which method should you use?

If you searched for how to change a WooCommerce email, a WooCommerce email customizer or a WooCommerce email editor: the built-in settings cover text, colours and logo, the block email editor is still early-access, and a plugin customizer is only worth it when a non-developer must edit layouts. Everything else below is a WooCommerce email template override or a hook.

GoalBest methodCode neededSurvives updates
Logo, colours, footer, sender nameWooCommerce > Settings > EmailsNoneYes
Subject, heading, extra paragraph per emailPer-email settings with placeholdersNoneYes
Visual layout editing per emailBlock Email Editor (alpha)NoneYes, but it is alpha
Add a line, block or field to existing emailsAction hooksSmall snippetYes
Change wording dynamicallyFilters (subject, heading, recipient)Small snippetYes
Rebuild the layout of one emailTemplate override in your child themePHP and HTMLNeeds review after template updates
A new email type (for example “ships tomorrow”)Custom WC_Email class in a pluginPlugin codeYes

Level 1: Change WooCommerce email settings, text and colours

Start here. According to the WooCommerce email settings documentation, the Emails tab gives you:

  • Sender options: the “From” name and address, plus an optional Reply-to. Use an address on your own domain.
  • Template options: logo, footer text and a colour palette (accent, email background, content background, heading and text, secondary text). With the “Email improvements” feature turned on you also get logo width, header alignment and font family. You can sync colours with your theme.
  • Email preview: pick any store email, preview it on desktop or mobile, and use “Send a test email” to send it to any address.
  • Per-email settings: click an email in the list to enable or disable it, set recipients, subject, heading, additional content, email type (HTML, plain text or multipart), and Cc and Bcc.

“Email improvements” shipped in WooCommerce 9.8, on by default for new installations and opt-in for existing stores under WooCommerce > Settings > Advanced > Features. If the extra design options are greyed out on an older store, that toggle is why.

Subjects, headings and additional content accept the documented placeholders {site_title}, {site_address}, {site_url}, {order_date} and {order_number}. For anything else, such as the customer’s first name, use the filter shown later.

Two recent changes: WooCommerce 11.2 removed Cc and Bcc from the Reset password, New account and Confirm email address emails, because they contain sensitive links. And the optional Order Withdrawal feature from 11.1 (off by default) adds a customer acknowledgement email and a store notification, both configurable under Settings > Emails since 11.2.

The block email editor: what is shipped and what is not

This is where many guides overclaim, so here is the exact status as of October 2026.

  • The block-based editor exists in WooCommerce core but is labelled alpha. The email editor integration docs say “The WooCommerce Email Editor is currently in alpha.”
  • It is opt-in. You enable it under WooCommerce > Settings > Advanced > Features > “Block Email Editor (alpha)”. It is not the default for new or existing stores.
  • The WooCommerce 11.0 release notes still list it among experimental features.
  • Third-party emails do not use the editor automatically. An extension has to opt each email ID in with the woocommerce_transactional_emails_for_block_editor filter. Otherwise the email still appears in the list but uses the classic system.

My advice: try it on staging, and do not switch a live store with heavy PHP overrides to an alpha editor. If you build a plugin that sends its own email, opting in is cheap:

add_filter( 'woocommerce_transactional_emails_for_block_editor', function ( $emails ) {
    $emails[] = 'raj_pre_shipment';
    return $emails;
} );

Level 2: WooCommerce email template overrides in your child theme

When you need a different layout, override the template. WooCommerce checks your theme before its own files: copy the plugin file to the same path inside a woocommerce folder in your child theme, without the templates part.

  1. Find the source file, for example wp-content/plugins/woocommerce/templates/emails/customer-completed-order.php.
  2. Copy it to wp-content/themes/your-child-theme/woocommerce/emails/customer-completed-order.php.
  3. For the plain-text version, copy templates/emails/plain/customer-completed-order.php to your-child-theme/woocommerce/emails/plain/customer-completed-order.php.
  4. Edit the copy, never the plugin file. Plugin files are replaced on every update.
  5. Send a test from the Emails screen and check both versions.

The shared parts are email-header.php, email-footer.php and email-styles.php. Overriding them changes every email at once.

The trade-off: core templates update and your copies do not. When WooCommerce changes a template, WooCommerce > Status lists your copy as outdated. I check that list on every maintenance visit. If you only need to add content, use a hook and skip this maintenance. Always use a child theme, or a theme update removes your overrides.

Level 3: hooks and filters

Hooks add or change output without copying templates. The ones I use most:

HookTypeArgumentsTypical use
woocommerce_email_headerAction$email_heading, $emailBanner or notice under the header
woocommerce_email_order_detailsAction$order, $sent_to_admin, $plain_text, $emailCore uses it to print the order table
woocommerce_email_before_order_tableAction$order, $sent_to_admin, $plain_text, $emailMessage above the items
woocommerce_email_after_order_tableAction$order, $sent_to_admin, $plain_text, $emailReturns info, next steps
woocommerce_email_order_metaAction$order, $sent_to_admin, $plain_text, $emailCustom fields such as delivery date
woocommerce_email_customer_detailsAction$order, $sent_to_admin, $plain_text, $emailExtra customer or address data
woocommerce_email_footerAction$emailLegal text or support links
woocommerce_email_subject_{email_id}Filter$subject, $object, $emailDynamic subject
woocommerce_email_heading_{email_id}Filter$heading, $object, $emailDynamic heading
woocommerce_email_recipient_{email_id}Filter$recipient, $object, $emailRoute admin emails

Put snippets in a small custom plugin or a code snippets plugin, not in a parent theme’s functions.php.

Change a subject with a filter

add_filter( 'woocommerce_email_subject_customer_completed_order', 'raj_completed_order_subject', 10, 3 );

function raj_completed_order_subject( $subject, $order, $email ) {
    if ( ! $order instanceof WC_Order ) {
        return $subject; // Email previews and resends can pass other objects.
    }
    return sprintf(
        /* translators: 1: customer first name, 2: order number */
        __( '%1$s, your order #%2$s is on its way', 'raj-emails' ),
        $order->get_billing_first_name(),
        $order->get_order_number()
    );
}

Note the __() wrapper. It keeps the string translatable, which matters if you sell in more than one language.

Add conditional content with an action

This adds a short returns notice to the completed order email, only for customers with an EU billing address. It handles the plain-text version too.

add_action( 'woocommerce_email_after_order_table', 'raj_eu_returns_notice', 10, 4 );

function raj_eu_returns_notice( $order, $sent_to_admin, $plain_text, $email ) {
    if ( $sent_to_admin || 'customer_completed_order' !== $email->id ) {
        return;
    }
    $eu = WC()->countries->get_european_union_countries();
    if ( ! in_array( $order->get_billing_country(), $eu, true ) ) {
        return;
    }
    $url  = home_url( '/returns/' );
    $text = __( 'You can withdraw from this purchase within 14 days. Details:', 'raj-emails' );

    if ( $plain_text ) {
        echo "\n" . esc_html( $text ) . ' ' . esc_url( $url ) . "\n";
    } else {
        printf( '<p>%s <a href="%s">%s</a></p>', esc_html( $text ), esc_url( $url ), esc_html__( 'Returns policy', 'raj-emails' ) );
    }
}

The same pattern works for product category, shipping method, order total or a meta field read with $order->get_meta(). Always check $email->id so content does not leak into other emails, and test refunded and cancelled orders. The wording and URL are placeholders; your actual terms decide the text.

Level 4: a custom email class

When you need a new email, for example a “ships tomorrow” notice, extend WC_Email. It then appears under Settings > Emails with the same subject, heading, enable and preview controls as core emails. The structure below follows the class outline in the email editor integration docs. Keep it in a plugin, not a theme.

// In your main plugin file.
add_filter( 'woocommerce_email_classes', function ( $emails ) {
    require_once __DIR__ . '/includes/class-raj-email-pre-shipment.php';
    $emails['Raj_Email_Pre_Shipment'] = new Raj_Email_Pre_Shipment();
    return $emails;
} );

// Let WooCommerce load the mailer when your event fires.
add_filter( 'woocommerce_email_actions', function ( $actions ) {
    $actions[] = 'raj_pre_shipment_event';
    return $actions;
} );
// includes/class-raj-email-pre-shipment.php
class Raj_Email_Pre_Shipment extends WC_Email {

    public function __construct() {
        $this->id             = 'raj_pre_shipment';
        $this->customer_email = true;
        $this->title          = __( 'Pre-shipment notice', 'raj-emails' );
        $this->description    = __( 'Sent the day before an order ships.', 'raj-emails' );
        $this->template_html  = 'emails/raj-pre-shipment.php';
        $this->template_plain = 'emails/plain/raj-pre-shipment.php';
        $this->template_base  = plugin_dir_path( __DIR__ ) . 'templates/';
        $this->placeholders   = array( '{order_number}' => '' );

        // WooCommerce fires "{action}_notification" for actions in woocommerce_email_actions.
        add_action( 'raj_pre_shipment_event_notification', array( $this, 'trigger' ), 10, 1 );

        parent::__construct();
    }

    public function get_default_subject() {
        return __( 'Order #{order_number} ships tomorrow', 'raj-emails' );
    }

    public function get_default_heading() {
        return __( 'Your order ships tomorrow', 'raj-emails' );
    }

    public function trigger( $order_id ) {
        $this->setup_locale();
        $order = wc_get_order( $order_id );
        if ( $order ) {
            $this->object                         = $order;
            $this->recipient                      = $order->get_billing_email();
            $this->placeholders['{order_number}'] = $order->get_order_number();
        }
        if ( $this->is_enabled() && $this->get_recipient() ) {
            $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
        }
        $this->restore_locale();
    }

    public function get_content_html() {
        return wc_get_template_html( $this->template_html, array(
            'order'              => $this->object,
            'email_heading'      => $this->get_heading(),
            'additional_content' => $this->get_additional_content(),
            'sent_to_admin'      => false,
            'plain_text'         => false,
            'email'              => $this,
        ), '', $this->template_base );
    }

    public function get_content_plain() {
        return wc_get_template_html( $this->template_plain, array(
            'order'              => $this->object,
            'email_heading'      => $this->get_heading(),
            'additional_content' => $this->get_additional_content(),
            'sent_to_admin'      => false,
            'plain_text'         => true,
            'email'              => $this,
        ), '', $this->template_base );
    }
}

Fire it with do_action( 'raj_pre_shipment_event', $order_id );, for example from an Action Scheduler job. Your templates can call do_action( 'woocommerce_email_header', $email_heading, $email ); and the order details hooks to match core styling, and a theme can still override them.

Translation: WPML, Polylang and Loco Translate

Before a customer email is built, WC_Email::setup_locale() switches to the site language, so an admin with a different profile language does not send emails in theirs. On a single-language store, use Loco Translate if you want to change core wording, and save its files in Loco’s protected location so updates do not wipe them.

For multilingual stores:

  • WPML with WooCommerce Multilingual: WPML’s documentation says customers receive emails in the language they ordered in, and email strings are translated in String Translation. A manual resend from the admin uses the admin language, so switch it first.
  • Polylang for WooCommerce: email setting strings are translated under Languages > Translations, in the WooCommerce group.
  • Custom code: wrap every string in __() with your own text domain, as in the examples above. Strings typed straight into a template override cannot be translated.

Plain-text versions

Each email can be HTML, plain text or multipart (both, the client picks). Every hook example above checks $plain_text for this reason. If you override an HTML template, override the matching file in emails/plain/ too.

Testing and deliverability

My testing routine:

  1. Use the built-in preview and “Send a test email” for layout.
  2. On local and staging, catch all mail with a tool such as Mailpit or Mailtrap so test orders never reach real customers.
  3. Place real test orders for each status (processing, completed, refunded, cancelled, failed) and each condition your snippets check.
  4. Check Gmail, Outlook and Apple Mail on desktop and mobile. Outlook on Windows is still the strictest renderer.
  5. Log sent mail on production so you can show what was sent.

Most “WooCommerce emails not sending” tickets I see are delivery problems. WordPress sends through the server’s PHP mail by default, which many hosts handle poorly. Route mail through a transactional provider such as Amazon SES, Postmark, Mailgun, SendGrid or Brevo, using WP Mail SMTP or the provider’s plugin.

Then authenticate your domain:

  • SPF: a DNS record listing which servers may send for your domain.
  • DKIM: a signature your provider adds, verified through a DNS key.
  • DMARC: a policy telling inboxes what to do when SPF or DKIM fails, with reports back to you.

Google’s published sender guidelines require SPF or DKIM for all senders, and all three for senders of more than 5,000 messages a day to Gmail. A small store should still set all three; it costs a few DNS records. Keep order emails on a separate sending stream from newsletters.

Regional compliance for store emails

Order emails are mostly transactional and lightly regulated. The risk starts when you add promotions or discount codes. This section is general information, not legal advice; check with a lawyer or accountant in each market.

MarketMain rulesWhat it means for WooCommerce emails
United StatesCAN-SPAM ActTransactional emails are largely exempt, but mixed emails are judged by primary purpose.
United KingdomUK GDPR, PECR, VAT rulesMarketing needs consent or the soft opt-in. VAT invoices go to VAT-registered business customers.
European UnionGDPR, ePrivacy rules, VAT DirectiveSame consent principles. Full invoice details are required for B2B supplies.
AustraliaSpam Act 2003, GST lawCommercial messages need consent, identification and unsubscribe. Tax invoices have fixed contents.

United States

The FTC CAN-SPAM compliance guide covers commercial messages; transactional messages are mostly exempt, read narrowly. For mixed emails the primary purpose decides, and an email leans commercial if the subject suggests a promotion or the transactional content is not at the beginning. Commercial email needs accurate headers and subjects, identification as an advertisement, a physical postal address, and an opt-out honoured within 10 business days. My rule: order details first, any cross-sell short and lower down.

United Kingdom and EU

Under PECR, the ICO’s electronic mail marketing guidance says marketing to individuals needs consent unless the soft opt-in applies: you collected the details during a sale, you market similar products, and you offered an opt-out at collection and in every message. The ICO says an opt-out in the order confirmation alone is not sufficient, so offer the choice at checkout. Never hide who you are, and keep personal data in emails to what the job needs.

On invoices: WooCommerce core does not produce VAT invoices, and an order email is not automatically one. In the UK, HMRC VAT Notice 700/21 requires a VAT invoice for standard or reduced rate supplies to VAT-registered customers, normally within 30 days. Retailers do not have to issue one to unregistered customers unless asked. A full invoice shows a unique sequential number, the supplier’s name, address and VAT registration number, and the other listed details. A simplified invoice is allowed up to £250. In the EU, the European Commission’s invoicing rules require an invoice for B2B supplies, with the sequential number, supplier and customer details, the VAT rate and amount, and the customer’s VAT number where reverse charge applies. If you sell B2B, use a PDF invoice plugin with sequential numbering and check its output against the official list.

Australia

The ACMA’s spam guidance sets three rules for commercial electronic messages under the Spam Act 2003: consent (express or inferred), accurate identification of the sender with contact details, and a working, free unsubscribe honoured within 5 working days. For GST, the ATO’s tax invoice page says a tax invoice must show that it is intended to be a tax invoice, the seller’s identity and ABN, the date, item descriptions with quantity and price, the GST amount (or “Total price includes GST” where GST is exactly one-eleventh of the price), and the extent each sale is taxable. Sales of $1,000 or more also need the buyer’s identity or ABN. A tax invoice is not required for sales of $82.50 or less including GST. If your order email doubles as a tax invoice, it needs that wording and your ABN.

Common mistakes I fix on client stores

  • Editing files inside wp-content/plugins/woocommerce/. The next update deletes the change.
  • Overriding a template to add one sentence when a hook would do it.
  • Forgetting the plain-text branch in hook callbacks.
  • Hard-coding English strings, which breaks multilingual stores.
  • Putting full marketing campaigns inside order emails, which turns transactional mail into commercial mail.
  • Sending from a free mailbox address with no SPF, DKIM or DMARC.

Frequently asked questions

How do I customize WooCommerce emails without code?

Go to WooCommerce > Settings > Emails. Set the sender details, logo, colours and footer text, then click each email to edit its subject, heading and additional content. If your store is older, turn on “Email improvements” under Advanced > Features for more design options. For visual layout editing you can test the alpha Block Email Editor on a staging site.

Is the WooCommerce block email editor ready for live stores?

As of WooCommerce 11.2 it is labelled alpha and is opt-in under Advanced > Features. It works, and it is getting regular updates, but alpha means behaviour can change. I use it on staging and on new, simple stores, and keep heavily customised stores on classic templates until it is marked stable.

Where do I put WooCommerce email template overrides?

Copy the file from wp-content/plugins/woocommerce/templates/emails/ to wp-content/themes/your-child-theme/woocommerce/emails/, keeping the same file name. Plain-text templates go in woocommerce/emails/plain/. Use a child theme so a theme update does not remove your changes.

Why is my WooCommerce email template override not working?

The usual causes are a wrong path (an extra templates folder, or the file in the parent theme while a child theme is active), editing the HTML file when the email is set to plain text, or a customiser plugin that replaces core templates. Check WooCommerce > Status, which lists the overrides it detects.

How do I add custom fields to WooCommerce order emails?

Hook into woocommerce_email_order_meta or woocommerce_email_after_order_table, read the value with $order->get_meta( 'your_key' ), and print it. Escape the output and handle the $plain_text argument. This keeps working through WooCommerce updates, unlike a template edit.

Why are WooCommerce emails going to spam?

Most often the store sends through the host’s PHP mail with no SPF, DKIM or DMARC for the From domain. Send through a transactional email provider over SMTP or API, authenticate your domain, and use a From address on that domain. Also keep heavy promotional content out of order emails.

Can a WooCommerce email serve as a VAT or GST tax invoice?

Only if it contains every detail the tax authority requires, and core WooCommerce emails do not include all of them by default. UK and EU VAT invoices need a sequential invoice number and the seller’s VAT number, and Australian tax invoices need the tax invoice wording and the seller’s ABN. Most stores use a PDF invoice plugin and attach the invoice to the relevant email.


If you need custom email types, conditional content, invoice attachments or a multilingual email setup built properly and tested, I can help. See my WooCommerce plugin development service to discuss what your store needs.

Leave a Reply