Email all customers who made a purchase, with Mechanic.

Mechanic is an automation development platform for Shopify. :)

Email all customers who made a purchase

by Isaac Bowen (team@usemechanic.com)

Need to reach customers who made a specific purchase? This task scans your order history, looking for orders that match the conditions you specify. For each qualifying order, the task sends an email to the customer, optionally linking to the product(s) ordered.

Runs when a user triggers the task and when a bulk operation finishes. Configuration includes search query for orders, product ids to look for, variant ids to look for, email subject, email body, add this tag to matching orders, test mode, and i certify that messages sent here are related to customer activity.

15-day free trial – unlimited tasks

Documentation

Configure "Search query for orders" with the same search query you might use in the Shopify admin area. For example:

  • Use processed_at:>=2019-01-01 processed_at:<2020-01-01 for every order in 2019
  • Use financial_status:paid for all paid orders
  • Use fulfillment_status:unshipped for all unshipped orders

Configure this task with product IDs and/or variant IDs, to have the task look for orders that contain any matching products and/or variants. Learn how to find these IDs.

Use ORDER_NAME in the email subject or body, to insert the name of the order (e.g. "#1234"). Use PRODUCT_TITLES or PRODUCT_TITLES_WITH_LINKS to list all products in the order.

Use "Test mode" to have Mechanic show you what emails it would send, if test mode were disabled.

This task requires you to certify that the messages sent are directly related to customer activity. Our email provider, Postmark, does not allow bulk messaging. Read more about their policy.

Developer details

Mechanic is designed to benefit everybody: merchants, customers, developers, agencies, Gurus, everybody.

That’s why we make it easy to configure automation without code, why we make it easy to tweak the underlying code once tasks are installed, and why we publish it all here for everyone to learn from.

Events
when a user triggers the task (mechanic/user/trigger)
when a bulk operation finishes (mechanic/shopify/bulk_operation)
Options
search query for orders, product ids to look for (number, array), variant ids to look for (number, array), email subject (required), email body (required, multiline), add this tag to matching orders, test mode (boolean), i certify that messages sent here are related to customer activity (boolean)
Script
{% comment %}
  Option order

  {{ options.search_query_for_orders }}
  {{ options.product_ids_to_look_for__number_array }}
  {{ options.variant_ids_to_look_for__number_array }}
  {{ options.email_subject__required }}
  {{ options.email_body__required_multiline }}
  {{ options.add_this_tag_to_matching_orders }}
  {{ options.test_mode__boolean }}
  {{ options.i_certify_that_messages_sent_here_are_related_to_customer_activity__boolean }}
{% endcomment %}

{% if event.topic == "mechanic/user/trigger" %}
  {% capture bulk_operation_query %}
    query {
      orders(
        query: {{ options.search_query_for_orders | json }}
      ) {
        edges {
          node {
            __typename
            id
            name
            email
            lineItems {
              edges {
                node {
                  __typename
                  id
                  product {
                    legacyResourceId
                    title
                    onlineStoreUrl
                  }
                  variant {
                    legacyResourceId
                  }
                }
              }
            }
          }
        }
      }
    }
  {% endcapture %}

  {% action "shopify" %}
    mutation {
      bulkOperationRunQuery(
        query: {{ bulk_operation_query | json }}
      ) {
        bulkOperation {
          id
          status
        }
        userErrors {
          field
          message
        }
      }
    }
  {% endaction %}
{% elsif event.topic == "mechanic/shopify/bulk_operation" %}
  {% assign line_items_by_order_id = hash %}

  {% assign orders = bulkOperation.objects | where: "__typename", "Order" %}
  {% assign qualifying_orders = array %}

  {% for object in bulkOperation.objects %}
    {% case object.__typename %}
    {% when "LineItem" %}
      {% assign order = object.__parent %}
      {% if line_items_by_order_id[order.id] == nil %}
        {% assign line_items_by_order_id[order.id] = array %}
      {% endif %}

      {% assign count = line_items_by_order_id[order.id].size %}
      {% assign line_items_by_order_id[order.id][count] = object %}
    {% endcase %}
  {% endfor %}

  {% for order in orders %}
    {% assign order_qualifies = true %}

    {% if order.email == blank %}
      {% assign order_qualifies = false %}
    {% endif %}

    {% if options.product_ids_to_look_for__number_array != blank %}
      {% assign product_ids_qualify = false %}
      {% for line_item in line_items_by_order_id[order.id] %}
        {% assign legacy_id_number = line_item.product.legacyResourceId | times: 1 %}
        {% if options.product_ids_to_look_for__number_array contains legacy_id_number %}
          {% assign product_ids_qualify = true %}
          {% break %}
        {% endif %}
      {% endfor %}

      {% unless product_ids_qualify %}
        {% assign order_qualifies = false %}
      {% endunless %}
    {% endif %}

    {% if options.variant_ids_to_look_for__number_array != blank %}
      {% assign variant_ids_qualify = false %}
      {% for line_item in line_items_by_order_id[order.id] %}
        {% assign legacy_id_number = line_item.variant.legacyResourceId | times: 1 %}
        {% if options.variant_ids_to_look_for__number_array contains legacy_id_number %}
          {% assign variant_ids_qualify = true %}
          {% break %}
        {% endif %}
      {% endfor %}

      {% unless variant_ids_qualify %}
        {% assign order_qualifies = false %}
      {% endunless %}
    {% endif %}

    {% if order_qualifies %}
      {% assign qualifying_orders[qualifying_orders.size] = order %}
    {% endif %}
  {% endfor %}

  {% assign test_mode_email_summaries = array %}

  {% if event.preview %}
    {% assign qualifying_orders[0] = hash %}
    {% assign qualifying_orders[0]["id"] = "gid://shopify/Order/1234567890" %}
    {% assign qualifying_orders[0]["name"] = "#1234" %}
    {% assign qualifying_orders[0]["email"] = "customer@example.com" %}

    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"] = array %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][0] = hash %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][0]["product"] = hash %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][0]["product"]["title"] = "Short Sleeve T-Shirt" %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][0]["product"]["onlineStoreUrl"] = "https://" | append: shop.domain %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][1] = hash %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][1]["product"] = hash %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][1]["product"]["title"] = "Medium Sleeve T-Shirt" %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][2] = hash %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][2]["product"] = hash %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][2]["product"]["title"] = "Long Sleeve T-Shirt" %}
    {% assign line_items_by_order_id["gid://shopify/Order/1234567890"][2]["product"]["onlineStoreUrl"] = "https://" | append: shop.domain %}
  {% endif %}

  {% for order in qualifying_orders %}
    {% assign email_to = order.email %}
    {% assign email_subject = options.email_subject__required | replace: "ORDER_NAME", order.name %}
    {% assign email_body = options.email_body__required_multiline | strip | newline_to_br | replace: "ORDER_NAME", order.name %}

    {% assign line_items_with_products = line_items_by_order_id[order.id] | where: "product" %}

    {% assign line_item_summaries = array %}

    {% for line_item in line_items_with_products %}
      {% assign summary = line_item.product.title %}

      {% if line_item.product.onlineStoreUrl != blank %}
        {% assign summary = '<a href="' | append: line_item.product.onlineStoreUrl | append: '">' | append: summary | append: '</a>' %}
      {% endif %}

      {% if forloop.last and forloop.index0 >= 2 %}
        {% assign summary = 'and ' | append: summary %}
      {% endif %}

      {% assign line_item_summaries[line_item_summaries.size] = summary %}
    {% endfor %}

    {% if line_item_summaries.size == 2 %}
      {% assign line_items_summary = line_item_summaries | join: " and " %}
    {% else %}
      {% assign line_items_summary = line_item_summaries | join: ", " %}
    {% endif %}

    {% assign line_items_summary_without_links = line_items_summary | strip_html %}

    {% assign email_body = email_body | replace: "PRODUCT_TITLES_WITH_LINKS", line_items_summary %}
    {% assign email_body = email_body | replace: "PRODUCT_TITLES", line_items_summary_without_links %}

    {% if options.test_mode__boolean %}
      {% assign test_mode_email_summary = hash %}
      {% assign test_mode_email_summary["to"] = email_to %}
      {% assign test_mode_email_summary["subject"] = email_subject %}
      {% assign test_mode_email_summary["body"] = email_body %}
      {% assign test_mode_email_summaries[test_mode_email_summaries.size] = test_mode_email_summary %}
    {% else %}
      {% action "email" %}
        {
          "to": {{ email_to | json }},
          "subject": {{ email_subject | json }},
          "body": {{ email_body | json }},
          "reply_to": {{ shop.customer_email | json }},
          "from_display_name": {{ shop.name | json }}
        }
      {% endaction %}

      {% if options.add_this_tag_to_matching_orders != blank %}
        {% action "shopify" %}
          mutation {
            tagsAdd(
              id: {{ order.id | json }}
              tags: {{ options.add_this_tag_to_matching_orders | json }}
            ) {
              userErrors {
                field
                message
              }
            }
          }
        {% endaction %}
      {% endif %}
    {% endif %}
  {% endfor %}

  {% if options.test_mode__boolean %}
    {% action "echo" %}
      {
        "message": "Found {{ qualifying_orders.size }} qualifying order(s)",
        "email_summaries": {{ test_mode_email_summaries | json }}
      }
    {% endaction %}

    {% if event.preview and options.add_this_tag_to_matching_orders != blank %}
      {% action "shopify" %}
        mutation {
          tagsAdd(
            id: "gid://shopify/Order/1234567890"
            tags: {{ options.add_this_tag_to_matching_orders | json }}
          ) {
            userErrors {
              field
              message
            }
          }
        }
      {% endaction %}
    {% endif %}
  {% endif %}
{% endif %}

{% unless event.preview %}
  {% if options.test_mode__boolean == false and options.i_certify_that_messages_sent_here_are_related_to_customer_activity__boolean == false %}
    {"error": "Our mail provider, Postmark, does not allow bulk messages that are not related to customer activity. For more information, see https://postmarkapp.com/blog/bulk-vs-transactional"}
  {% endif %}
{% endunless %}
Mechanic tasks are written in Liquid, which makes them easy to write and easy to modify. Learn more about our platform.
Defaults
Search query for orders
financial_status:paid processed_at:>=2019-10-01
Email subject
A note about ORDER_NAME
Email body
Hello,

Thanks for ordering PRODUCT_TITLES_WITH_LINKS. We appreciate it. :)

Cheers,
{{ shop.name }}
Test mode
true