Skip to Content
EmailsWooCommerce

How to Customize WooCommerce Emails: A Practical Developer Guide

How to Customize WooCommerce Emails: A Practical Developer Guide

Every WooCommerce store sends transactional emails — order confirmations, shipping notifications, password resets, refund notices. Out of the box, these emails look generic, carry no brand personality, and miss opportunities to drive repeat purchases or reduce support tickets. Learning how to customize WooCommerce emails is one of the highest-leverage things you can do as a store owner or developer: small changes compound across every order.

There are three distinct ways to customize WooCommerce emails, and picking the right one for each change saves hours of pointless work. The Customizer-style WooCommerce email settings handle basic branding (logo, colors, footer) without code. Template overrides let you restructure email layouts via theme files. Code hooks let you inject dynamic data, conditional content, and entirely new email types.

Quick verdict: use the Settings → Emails panel for logo + colors + footer text. Use template overrides when you need to restructure how an email looks. Use code hooks when you need conditional content, custom fields, or new email triggers. This guide walks through all three approaches with the specific files, hooks, and patterns that work today.

customize WooCommerce emails: quick reference

customize WooCommerce emails — visual reference and overview

If you are evaluating customize WooCommerce emails for your next project, you are weighing real trade-offs between cost, complexity, ownership, and time-to-launch. The right customize WooCommerce emails decision depends on a handful of variables — team capacity, scope clarity, and how much ongoing maintenance you can absorb. The summary below is the 60-second version; the rest of this guide unpacks the nuance.

  • customize WooCommerce emails pricing typically ranges based on scope clarity, integration count, and ongoing support requirements.
  • customize WooCommerce emails timelines vary from days (small scope) to months (enterprise scope) depending on complexity.
  • The biggest variable in customize WooCommerce emails is requirements clarity at the brief stage — vague briefs produce vague quotes.
  • Vendor selection for customize WooCommerce emails matters more than tool selection — the right team beats the right stack.
  • customize WooCommerce emails ROI is positive when scope is bounded, deliverables are specified, and success criteria are measurable.

For complementary perspectives on customize WooCommerce emails, the WooCommerce official email settings documentation and WooCommerce template structure reference resources cover adjacent angles worth reviewing alongside this guide. They focus on the underlying technology and standards — this post focuses on the customize WooCommerce emails decision specifically.

When you revisit your customize WooCommerce emails approach in 12 to 24 months, three signals usually indicate a refresh is justified. First, the original brief no longer matches business reality — product, audience, or operational scope has shifted. Second, the underlying technology has moved forward enough that the customize WooCommerce emails decision made under previous constraints would be different today. Third, ongoing maintenance overhead has crept up beyond what was forecast at launch. None of these are emergencies on their own; together they signal it is time to revisit fundamentals rather than patch around them.

The 12 default WooCommerce emails you can customize

WooCommerce ships with twelve transactional email types. Knowing which one fires when is the foundation of intelligent customization.

Email typeFires whenSent to
New orderOrder placedAdmin
Cancelled orderOrder cancelledAdmin
Failed orderPayment failedAdmin
Order on-holdAwaiting paymentCustomer
Processing orderPayment receivedCustomer
Completed orderOrder fulfilledCustomer
Refunded orderRefund issuedCustomer
Customer invoice / paymentManual or unpaid orderCustomer
Customer noteNote added to orderCustomer
Reset passwordPassword reset requestedCustomer
New accountAccount createdCustomer
Low / out of stockStock threshold hitAdmin

Each email is a separate class extending WC_Email, with its own subject, heading, template, and recipient. When you customize WooCommerce emails, you target one of these specific classes — not a global email system.

The three ways to customize WooCommerce emails

Pick the right level of customization for the change you need. Going deeper than necessary wastes time and creates maintenance debt.

  • Level 1 — WooCommerce Settings (no code): change the header image, base color, footer text, and per-email subjects + headings. Right path for branding-only changes.
  • Level 2 — Template overrides: copy email template files into your theme and edit the HTML/structure directly. Right path when you need to restructure layout, add new sections, or remove default sections.
  • Level 3 — Code hooks (PHP): use WooCommerce filters and actions to inject dynamic data, modify subjects programmatically, add custom fields, or build entirely new email types. Right path for anything that depends on the order, customer, product, or business logic.

Level 1: WooCommerce Settings → Emails (the no-code path)

The first stop for any WooCommerce email customization is WooCommerce → Settings → Emails. This panel handles the changes 70% of stores actually need without touching a line of code.

  • Email sender options — change the “from” name and address (use your store email, not WordPress’s default wordpress@yoursite.com).
  • Header image — paste a URL to your logo. WooCommerce centers it at the top of every email. Use a transparent PNG sized around 300×80 for best results.
  • Footer text — appears at the bottom of every email. Replace the default “Powered by WooCommerce” with your tagline, support email, or unsubscribe note.
  • Base color / background / body color — set the email’s brand colors site-wide.
  • Per-email settings — click any specific email (e.g., “Completed order”) to edit its subject, heading, recipient, and enable/disable it.

Subject and heading variables: WooCommerce subjects and headings support placeholder variables like {site_title}, {order_number}, {order_date}, {customer_first_name}. Use them in the Settings panel for dynamic personalization without code.

Level 2: WooCommerce email template override hierarchy

Every WooCommerce email is rendered from a PHP template. WooCommerce looks for these templates in a specific priority order, and the first match wins. Knowing the hierarchy is essential when you edit WooCommerce email templates.

  • 1. Child themewp-content/themes/your-child-theme/woocommerce/emails/
  • 2. Parent themewp-content/themes/your-theme/woocommerce/emails/
  • 3. WooCommerce pluginwp-content/plugins/woocommerce/templates/emails/ (the defaults)

To override an email template, copy the file from the WooCommerce plugin folder into your theme’s woocommerce/emails/ folder. WooCommerce automatically uses your version. Never edit the plugin’s files directly — every WooCommerce update will overwrite your changes.

How to override a WooCommerce email template (step by step)

Concrete walkthrough for the most common task: customizing the “Completed order” customer email.

  • 1. Locate the source template at wp-content/plugins/woocommerce/templates/emails/customer-completed-order.php
  • 2. Create the folder wp-content/themes/your-child-theme/woocommerce/emails/ if it does not exist
  • 3. Copy customer-completed-order.php into that folder
  • 4. Edit the copy — change the greeting, add a “leave a review” CTA, insert a related-products section, anything you need
  • 5. Send a test email (place a test order and complete it) to verify the override is picked up

Sub-templates also override: The shared email components — header, footer, email styles, order details, customer details — are separate template files (email-header.php, email-footer.php, email-styles.php). Override these to change branding across ALL emails in one place, instead of editing each individual email template.

Level 3: Code hooks for dynamic WooCommerce email customization

When you need conditional logic, dynamic data from the order, or behavior changes — hooks are the right tool. The hooks I use most often when customizing WooCommerce emails:

Example — change the subject of completed-order emails dynamically:

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

function raj_completed_order_subject( $subject, $order ) {
    if ( ! is_object( $order ) ) {
        return $subject;
    }
    return sprintf(
        'Your order #%s is on the way!',
        $order->get_order_number()
    );
}

Drop that into your child theme’s functions.php or a small custom plugin. The subject now changes per-order based on the order number. The same pattern works with woocommerce_email_subject_{email_id} for any email type.

HookUse case
woocommerce_email_subject_{email_id}Modify subject line dynamically
woocommerce_email_heading_{email_id}Modify in-email heading dynamically
woocommerce_email_recipient_{email_id}Add BCC, CC, or change recipient based on order data
woocommerce_email_before_order_tableInject custom content above the order table
woocommerce_email_after_order_tableInject custom content below the order table
woocommerce_email_order_metaAdd custom order meta fields to the email body
woocommerce_email_customer_detailsCustomize the customer billing/shipping section
woocommerce_mail_callbackReplace WooCommerce’s mail-sending function entirely

Adding custom fields and ACF data to WooCommerce emails

A common requirement: include order custom fields, ACF (Advanced Custom Fields) values, or delivery-date pickers in the email. Hook into woocommerce_email_order_meta to add these as new meta rows under the order details.

  • Capture the field value with $order->get_meta('_your_field_key')
  • Format it for display (date format, currency, sanitize)
  • Echo it as an HTML row that matches WooCommerce’s email styling
  • For ACF fields, pull via get_field('field_name', $order->get_id())

Custom field rendering should respect the email’s text/HTML format. Both formats fire the same hook but receive a $plain_text boolean — branch your output accordingly so plain-text recipients see clean text without HTML tags.

Complete working example — add a delivery date stored as order meta to every order email:

add_action( 'woocommerce_email_order_meta', 'raj_email_delivery_date', 10, 3 );

function raj_email_delivery_date( $order, $sent_to_admin, $plain_text ) {
    $delivery_date = $order->get_meta( '_delivery_date' );
    if ( ! $delivery_date ) {
        return;
    }

    if ( $plain_text ) {
        echo "\n" . 'Delivery date: ' . esc_html( $delivery_date ) . "\n";
    } else {
        echo '<p style="margin-top:1em;">';
        echo '<strong>Delivery date:</strong> ' . esc_html( $delivery_date );
        echo '</p>';
    }
}

Conditional content based on order data

Sometimes you want different content per order type — for example, a “redeem your gift card” section only when a gift card product is in the order, or a “schedule installation” CTA only for orders containing physical equipment.

  • Inspect order items with $order->get_items() and check product categories, attributes, or custom flags
  • Build the conditional HTML in your hook callback
  • Return the HTML so WooCommerce embeds it in the email body at the chosen position
  • Test edge cases — empty orders, mixed item types, refunded items

Example — show a gift-card redemption block only when the order contains a gift card product:

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

function raj_email_gift_card_note( $order, $sent_to_admin, $plain_text, $email ) {
    $has_gift_card = false;
    foreach ( $order->get_items() as $item ) {
        $product = $item->get_product();
        if ( $product && has_term( 'gift-cards', 'product_cat', $product->get_id() ) ) {
            $has_gift_card = true;
            break;
        }
    }
    if ( ! $has_gift_card ) {
        return;
    }

    if ( $plain_text ) {
        echo "\n--\nRedeem your gift card at: " . home_url( '/gift-card-redeem/' ) . "\n";
    } else {
        echo '<p style="background:#f5f9ff;padding:14px;border-radius:6px;">';
        echo '<strong>Redeem your gift card:</strong> ';
        echo '<a href="' . esc_url( home_url( '/gift-card-redeem/' ) ) . '">Visit the redeem page</a>';
        echo '</p>';
    }
}

Customizing email recipients (BCC, CC, multiple admins)

By default, admin emails go to a single recipient set in WooCommerce → Settings → Emails. For multi-admin notifications, fulfillment forwarding, or order-specific routing, use the woocommerce_email_recipient_{email_id} filter.

  • Return a comma-separated string of email addresses
  • Branch on order data (region, total, product category) for routing — different warehouses get different orders
  • Always include the original recipient unless replacing intentionally
  • For BCC, append "bcc:archive@yourstore.com" only when supported by your mail transport

Example — route new-order emails based on order total and shipping region:

add_filter( 'woocommerce_email_recipient_new_order', 'raj_route_new_order_email', 10, 2 );

function raj_route_new_order_email( $recipient, $order ) {
    if ( ! is_object( $order ) ) {
        return $recipient;
    }

    // Always BCC the fulfillment team.
    $extra = array( 'fulfillment@yourstore.com' );

    // Route high-value orders to a senior manager too.
    if ( $order->get_total() >= 500 ) {
        $extra[] = 'manager@yourstore.com';
    }

    // Region-based routing — example: ship-to-CA orders go to the West coast warehouse.
    if ( 'CA' === $order->get_shipping_state() ) {
        $extra[] = 'westcoast@yourstore.com';
    }

    return implode( ',', array_merge( array( $recipient ), $extra ) );
}

Creating a completely custom WooCommerce email type

When the 12 default emails do not cover your need — for example, a “your order ships tomorrow” pre-shipment heads-up, or a “tracking number updated” notification — you can register a new email class.

  • 1. Create a class extending WC_Email with id, title, description, template paths
  • 2. Override trigger() with the logic that decides when the email fires
  • 3. Hook your trigger to a WooCommerce action (e.g., woocommerce_order_status_processing)
  • 4. Register the class via the woocommerce_email_classes filter
  • 5. Add template files for HTML + plain-text versions
  • 6. Test from a clean state — the email should appear in Settings → Emails like the defaults

Custom email classes belong in a plugin (not the theme) so they survive theme switches. Treat the email class as its own small module with its own template files, settings, and tests.

Skeleton — a custom “Pre-shipment notification” email class:

add_filter( 'woocommerce_email_classes', 'raj_register_pre_shipment_email' );

function raj_register_pre_shipment_email( $email_classes ) {
    require_once plugin_dir_path( __FILE__ ) . 'class-wc-email-pre-shipment.php';
    $email_classes['WC_Email_Pre_Shipment'] = new WC_Email_Pre_Shipment();
    return $email_classes;
}

// class-wc-email-pre-shipment.php — the email class itself
class WC_Email_Pre_Shipment extends WC_Email {

    public function __construct() {
        $this->id             = 'pre_shipment_notification';
        $this->title          = 'Pre-shipment notification';
        $this->description    = 'Sent 24 hours before scheduled shipment.';
        $this->customer_email = true;
        $this->template_html  = 'emails/pre-shipment.php';
        $this->template_plain = 'emails/plain/pre-shipment.php';
        $this->template_base  = plugin_dir_path( __FILE__ ) . 'templates/';

        // Fire this email from any custom event your plugin emits.
        add_action( 'raj_pre_shipment_event', array( $this, 'trigger' ), 10, 1 );

        parent::__construct();
    }

    public function trigger( $order_id ) {
        $order = wc_get_order( $order_id );
        if ( ! $order ) {
            return;
        }

        $this->object    = $order;
        $this->recipient = $order->get_billing_email();

        if ( $this->is_enabled() && $this->get_recipient() ) {
            $this->send(
                $this->get_recipient(),
                $this->get_subject(),
                $this->get_content(),
                $this->get_headers(),
                $this->get_attachments()
            );
        }
    }

    public function get_default_subject() {
        return 'Heads up — your order #{order_number} ships tomorrow';
    }

    public function get_default_heading() {
        return 'Your order ships tomorrow';
    }
}

After registering this class, “Pre-shipment notification” appears in WooCommerce → Settings → Emails alongside the 12 defaults — with its own enable toggle, subject, heading, and template editor. Fire the email from your business logic by doing do_action( 'raj_pre_shipment_event', $order_id ) wherever shipment is scheduled.

WooCommerce block-based email templates

WooCommerce 8.x introduced block-based email templates as an opt-in feature, with broader adoption ongoing. Block-based emails replace the PHP template files with Gutenberg block compositions, edited visually in the Site Editor instead of code.

  • Pros — visual editing, no PHP knowledge required, design tokens shared with the site
  • Cons — limited dynamic content compared to PHP templates, smaller ecosystem of patterns, ongoing development
  • When to adopt — for stores starting fresh or already invested in block themes
  • When to stay on PHP templates — for stores with significant existing customizations or complex conditional logic

Testing WooCommerce emails locally

Production stores rarely want test order emails firing to real customer addresses. Three reliable local testing approaches:

  • MailHog / MailCatcher — local SMTP servers that capture all outgoing mail in a web UI. Free, Docker-friendly, perfect for development
  • Mailtrap — hosted fake SMTP for staging environments. Catches every email; lets your team preview without sending to customers
  • WP Mail Logging plugin — logs every email WordPress sends to the admin UI for review
  • Email Log plugin — alternative logger with HTML preview

Always test BOTH formats: WooCommerce sends both HTML and plain-text versions of every email. Many customizations break one or the other. Preview both formats before declaring the customization done — Mailtrap and MailHog both show plain-text alongside HTML.

Production: transactional email services

WordPress’s default wp_mail() uses your server’s PHP mail. For production, this means inconsistent delivery, frequent spam classification, and no tracking. Use a transactional email service instead.

ServiceFree tierBest for
SendGrid100 emails/dayHigh volume, strong API
Mailgun5,000 emails/mo first 3 monthsDeveloper-friendly
Amazon SES62,000 emails/mo from EC2AWS-native stores, lowest cost at scale
Postmark100 emails/moBest deliverability, premium pricing
WP Mail SMTP pluginConnects to any of the aboveEasiest setup for non-developers

Configure DKIM, SPF, and DMARC records on your sending domain. Without these, even premium services hit spam folders. WP Mail SMTP’s configuration wizard handles the setup correctly for most stores.

Common mistakes when customizing WooCommerce emails

Patterns that look correct but cause real problems in production:

  • Editing plugin files directly — wiped on every WooCommerce update. Always override via theme or hooks
  • Forgetting plain-text version — many email clients render plain-text by default. Test it; do not let HTML markup leak through
  • Hardcoding URLs — use home_url() or get_permalink() so URLs work across local/staging/production
  • Sending sensitive data unencrypted — never include payment details, full card numbers, or auth tokens in emails
  • Skipping the recipient hook for admin notifications — when your team grows, missing the hook means the new admin does not get order notifications
  • Not handling refunds + cancellations — custom content blocks should respect order status; do not promote products in a refund email
  • Skipping i18n — wrap all custom strings in __() or esc_html__() so multilingual stores translate correctly

Basics — FAQs

How do I customize the WooCommerce email header logo?

Go to WooCommerce → Settings → Emails. Paste your logo URL into the Header image field. Use a transparent PNG sized around 300×80 pixels for best results across email clients. The change applies to every WooCommerce email automatically.

Where are WooCommerce email templates stored?

Default templates live at wp-content/plugins/woocommerce/templates/emails/. To override them, copy the file into your child theme at wp-content/themes/your-child-theme/woocommerce/emails/ — WooCommerce automatically uses the theme version. Never edit the plugin folder directly.

Can I customize WooCommerce emails without coding?

Yes — for branding changes (logo, colors, footer text, subject lines), WooCommerce → Settings → Emails covers everything without code. For layout restructuring you need template overrides (some HTML knowledge). For dynamic content or new email types you need PHP hooks.

Advanced — FAQs

How do I add custom fields to WooCommerce order emails?

Hook into woocommerce_email_order_meta. Access the order with $order->get_meta('_your_field'), format the value, and echo it as a styled HTML row. For ACF fields, use get_field('field_name', $order->get_id()) instead. Branch on the $plain_text parameter so plain-text recipients see clean text.

How do I create a completely custom WooCommerce email type?

Create a class extending WC_Email with its own id, title, template paths, and trigger logic. Hook the trigger to a WooCommerce action (status change, custom event). Register your class via the woocommerce_email_classes filter. Add HTML + plain-text template files. Once registered, the email appears in Settings → Emails like the defaults.

Can I customize the wc_mail() function?

Yes — but rarely needed. Hook into woocommerce_mail_callback to replace WooCommerce’s mail-sending function. Most stores instead route WooCommerce mail through a transactional service (SendGrid, Mailgun) via the WP Mail SMTP plugin, which is simpler and more reliable.

Testing & deployment — FAQs

How do I test WooCommerce emails locally?

Use MailHog or MailCatcher — local SMTP servers that capture all outgoing email in a web UI without sending anywhere real. For staging environments, Mailtrap is a hosted equivalent. Also install WP Mail Logging or Email Log for logged-in admin access to recent emails. Always preview both HTML AND plain-text formats before declaring a customization done.

Why are my WooCommerce emails going to spam?

Three usual causes. (1) Sending from your server’s default PHP mail — switch to a transactional service like SendGrid or Amazon SES. (2) Missing DKIM, SPF, DMARC records on your sending domain — configure them through your DNS provider. (3) The “from” address does not match the sending domain — set sender email to match your verified domain. WP Mail SMTP’s setup wizard handles all three correctly.

Will customizing WooCommerce emails affect my checkout speed?

Email sending happens AFTER checkout completes — emails are queued and sent asynchronously, so customization complexity does not slow down the customer-facing checkout experience. Heavy email customization (large templates, many hooks, complex queries) can slow background mail processing on high-volume stores; mitigate with a transactional service that handles queuing externally.

Need custom WooCommerce email development done by an expert?


See my WooCommerce plugin customization service →

Leave a Reply