Shopify API: How do I send customer an email about product being shipped?

Viewed 1685

I'm trying to send a customer an email with order tracking information by updating the order fulfillment but the email is not being sent out. I can retrieve the fulfillment and add a tracking code and it saves properly but the status doesn't update.

 fulfillment_id = 3252574519475
 shopify_order_id = 3683332686003

 fulfillment = shopify.Fulfillment.find(fulfillment_id,order_id=shopify_order_id)
 fulfillment.tracking_numbers = [tracking_number]
 fulfillment.tracking_company = tracking_company
 fulfillment.notify_customer = "true"
 fulfillment.status = "success"
 fulfillment.shipment_status = "delivered"
 result = fulfillment.save()

When I visit https://dev-store.myshopify.com/admin/orders/3683332686003/fulfillments.json I see the tracking_numbers update along with the tracking_company and tracking_urls but the status is still open:

 {
    "fulfillments": [{
        "id": 3252573110451,
        "order_id": 3683332686003,
        "status": "success",
        "created_at": "2021-03-22T14:36:55-04:00",
        "service": "gift_card",
        "updated_at": "2021-03-22T14:36:56-04:00",
        "tracking_company": null,
        "shipment_status": null,
        "location_id": 61514940595,
        "line_items": [{
            "id": 9689309610163,
            "variant_id": 39396209983667,
            "title": "$100 ta E-Gift Card",
            "quantity": 1,
            "sku": null,
            "variant_title": "$100.00 USD",
            "vendor": "A",
            "fulfillment_service": "gift_card",
            "product_id": 6571217256627,
            "requires_shipping": false,
            "taxable": false,
            "gift_card": true,
            "name": "$100 ta E-Gift Card - $100.00 USD",
            "variant_inventory_management": null,
            "properties": [],
            "product_exists": true,
            "fulfillable_quantity": 0,
            "grams": 0,
            "price": "95.00",
            "total_discount": "0.00",
            "fulfillment_status": "fulfilled",
            "price_set": {
                "shop_money": {
                    "amount": "95.00",
                    "currency_code": "USD"
                },
                "presentment_money": {
                    "amount": "95.00",
                    "currency_code": "USD"
                }
            },
            "total_discount_set": {
                "shop_money": {
                    "amount": "0.00",
                    "currency_code": "USD"
                },
                "presentment_money": {
                    "amount": "0.00",
                    "currency_code": "USD"
                }
            },
            "discount_allocations": [],
            "tax_lines": []
        }],
        "tracking_number": null,
        "tracking_numbers": [],
        "tracking_url": null,
        "tracking_urls": [],
        "receipt": {
            "gift_cards": [{
                "id": 483988799667,
                "line_item_id": 9689309610163,
                "masked_code": "•••• •••• •••• 74e2"
            }]
        },
        "name": "#1013.1"
    }, {
        "id": 3252574519475,
        "order_id": 3683332686003,
        "status": "open",
        "created_at": "2021-03-22T14:37:23-04:00",
        "service": "manual",
        "updated_at": "2021-03-22T14:49:45-04:00",
        "tracking_company": "UPS",
        "shipment_status": null,
        "location_id": 61514940595,
        "line_items": [{
            "id": 9689309642931,
            "variant_id": 39396224663731,
            "title": "The Pack",
            "quantity": 1,
            "sku": "FM-001",
            "variant_title": null,
            "vendor": "A",
            "fulfillment_service": "manual",
            "product_id": 6571220402355,
            "requires_shipping": true,
            "taxable": true,
            "gift_card": false,
            "name": "The Pack",
            "variant_inventory_management": null,
            "properties": [],
            "product_exists": true,
            "fulfillable_quantity": 0,
            "grams": 3629,
            "price": "111.99",
            "total_discount": "0.00",
            "fulfillment_status": null,
            "price_set": {
                "shop_money": {
                    "amount": "111.99",
                    "currency_code": "USD"
                },
                "presentment_money": {
                    "amount": "111.99",
                    "currency_code": "USD"
                }
            },
            "total_discount_set": {
                "shop_money": {
                    "amount": "0.00",
                    "currency_code": "USD"
                },
                "presentment_money": {
                    "amount": "0.00",
                    "currency_code": "USD"
                }
            },
            "discount_allocations": [],
            "tax_lines": []
        }],
        "tracking_number": "1Z6R96W802851935",
        "tracking_numbers": ["1Z6R96W802851935"],
        "tracking_url": "https:\/\/www.ups.com\/WebTracking?loc=en_US\u0026requester=ST\u0026trackNums=1Z6R96W80302851935",
        "tracking_urls": ["https:\/\/www.ups.com\/WebTracking?loc=en_US\u0026requester=ST\u0026trackNums=1Z6R96W80302851935"],
        "receipt": {},
        "name": "#1013.2"
    }]
 }
 

How do I get shopify to send the customer an email with the tracking number and update the status of the fulfillment from open to success so that the whole order is set to fulfilled? I've been manually creating orders on the store im not sure if that has anything to do with it.

I'm using this Python package https://github.com/Shopify/shopify_python_api

2 Answers

If you have set "notify_customer" to true at the fulfillment, that's the first thing. You should then create a so-called fullfillment event with "status" set to "in_transit". As a result of that, Shopify will:

  • Send an email to the customer
  • Set the fulfillment status to "in_transit"
  • Display the new status on the order status page

Creation of a fulfillment event is described quite well In Shopify's API documentation at: https://shopify.dev/docs/admin-api/rest/reference/shipping-and-fulfillment/fulfillmentevent

With the help of fulfillment events you can also set further status values like "out_for_delivery" and "delivered".

As far as i see shopify doesn't have any relation with smpt so another lib is required, on python is quite easy to send emails; jinja is for convenience, you can send a full on html page.

from email.mime.text import MIMEText
from email.header import Header
import smtplib
import jinja2
import ssl
import os


class Shipment_Email:

    mail_addr = 'smtp.mail.yahoo.com'
    mail_port = 465

    __email = str('your_name@yahoo.com')
    __passw = str('your_api_password')

    def send_to(self, to, sub, data):
        content = self.template.render(data=data)
        msg = MIMEText(content, 'html', 'utf-8')
        msg['Subject'] = Header(sub, 'utf-8')
        msg['From'] = self.__email
        if not isinstance(to, str):
            msg['To'] = ', '.join(to)
        else:
            msg['To'] = to
        self.server.sendmail(self.__email, to, msg.as_string())

    @staticmethod
    def load_template(src):
        if os.path.isfile(src):
            with open(src, 'r') as file:
                return jinja2.Template(file.read())

    def __init__(self, debug=False):
        ssl_context = ssl.create_default_context()
        self.server = smtplib.SMTP_SSL(self.mail_addr, self.mail_port, 
                                       context=ssl_context)
        self.server.login(self.__email, self.__passw)
        self.server.set_debuglevel(debug)
        self.template = self.load_template('./index.html')

    def exit(self):
        self.server.quit()


if __name__ == '__main__':
    mail_hanlde = Shipment_Email(debug=True)
    mail_hanlde.send_to('a_target@yahoo.com',
        'Shopping list', {
            'Name': 'Alex',
            'Product': {
                'Coffe': 8.50,
                'Keyboard': 150
            }
        })
    mail_hanlde.exit()

index.html :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <style> p { margin-left: 20px } </style>
</head>
<body>
<h4>{{ data['Name']}}'s shoping list:</h4>
    {% for item in data['Product'] %}
        <p>{{ item }} : {{data['Product'][item]}} eu</p>
    {% endfor %}
</body>
</html>

Working mail

For this to work on yahoo mail you need to get a custom device password, so tick the marked option and use that password instead of the account, they are not the same.

Yahoo api password

Related