How to Create DHL Express Customs Documents From an Email Order

When an international order lands in a connected Gmail mailbox, this Spojit workflow extracts the line items with an Agent-mode node, books a customs-declarable DHL Express shipment, and emails the customs paperwork back to the customer.

What This Integration Does

Cross-border fulfilment stalls on paperwork. Someone has to read the order, work out the declared value and country of origin for each item, key it into the carrier, and then forward the customs documents to the buyer. This workflow removes that manual step: every international order that arrives by email becomes a fully declared DHL Express shipment with the customs commercial invoice sent straight to the customer, with no copy-paste between an inbox and a shipping portal.

An Email trigger polls a connected Gmail mailbox and fires once per matching message. A Connector node in Agent mode reads the email body and returns a clean list of line items as JSON. A second Connector node calls DHL Express in Direct mode to create the shipment and generate the label and customs documents, and a Send Email node delivers the paperwork to the buyer. The run leaves a booked DHL shipment plus an outbound email; because Spojit deduplicates each polled message, the same order email will not be booked twice if the workflow re-runs.

Prerequisites

  • A connected Gmail (trigger) connection. Add it under Connections -> Add connection -> Gmail (trigger). Read-only access is enough unless you want to mark messages as read after processing.
  • A Shopify connection (API key), used to confirm the order and read shipping address details when the email only carries an order number.
  • A DHL Express connection with a MyDHL account number that is enabled for dutiable (international) shipments.
  • The customer email recipients you reply to must be on the org allowlist under Settings -> General -> Email recipients if you send outside your own domain.
  • Your shipper details: company name, address, postal code, and country code (ISO 3166-1 alpha-2), ready to drop into the DHL payload.

Step 1: Trigger on the incoming order email

Add a Trigger node and set its type to Email. Pick the connected Gmail mailbox and the folder that international orders arrive in. Set the poll interval (1 to 60 minutes; default 2). To avoid noise, set the optional From allowlist to your store's order-notification address and a Subject regex such as New order #\d+. The trigger output gives you {{ input.subject }}, {{ input.textBody }}, {{ input.from }}, and {{ input.receivedAt }}, which downstream nodes reference.

Step 2: Extract the line items with an Agent-mode Connector node

Add a Connector node, choose your e-commerce connector (such as Shopify), and switch it to Agent mode so an AI agent reads the unstructured email and returns structured data. In the prompt, paste the email body and ask for the items. Define a Response Schema so the output is reliable JSON rather than prose. Example prompt:

Read this order email and return each line item with its
description, quantity, unit price, currency, and country of
manufacture. If a field is missing, leave it null.

Email:
{{ input.textBody }}

Set the Response Schema to force the shape you map later:

{
  "type": "object",
  "properties": {
    "orderNumber": { "type": "string" },
    "currency": { "type": "string" },
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "description": { "type": "string" },
          "quantity": { "type": "number" },
          "unitPrice": { "type": "number" },
          "countryOfOrigin": { "type": "string" }
        }
      }
    }
  }
}

The structured result is now available as {{ extract.items }} and {{ extract.orderNumber }} for the rest of the workflow.

Step 3: Confirm the order and ship-to address in Shopify

Add a Connector node for Shopify in Direct mode and pick the get-order tool. Map the order identifier from {{ extract.orderNumber }}. This confirms the order exists and returns the authoritative shipping address, customer name, and email, so you do not rely on the email body for the delivery address. Reference the result downstream as {{ order.shipping_address }} and {{ order.email }}. If the email already contains a complete, trusted ship-to address, you can skip this step.

Step 4: Book the customs-declarable DHL Express shipment

Add a Connector node for DHL Express in Direct mode and choose the create-shipment tool. This tool takes one payload object following the MyDHL ShipmentRequest schema. The customs declaration lives in the content block: set isCustomsDeclarable to true, supply the declaredValue and declaredValueCurrency, and list every line item under exportDeclaration.lineItems using the data from {{ extract.items }}. A minimal payload looks like this:

{
  "plannedShippingDateAndTime": "{{ input.receivedAt }}",
  "productCode": "P",
  "customerDetails": {
    "shipperDetails": { "...your shipper address..." },
    "receiverDetails": {
      "postalAddress": {
        "cityName": "{{ order.shipping_address.city }}",
        "countryCode": "{{ order.shipping_address.country_code }}",
        "postalCode": "{{ order.shipping_address.zip }}"
      }
    }
  },
  "content": {
    "isCustomsDeclarable": true,
    "declaredValue": 240.00,
    "declaredValueCurrency": "{{ extract.currency }}",
    "exportDeclaration": {
      "lineItems": [
        {
          "description": "{{ item.description }}",
          "quantity": { "value": 2, "unitOfMeasurement": "PCS" },
          "price": 120.00,
          "manufacturerCountry": "{{ item.countryOfOrigin }}"
        }
      ]
    },
    "packages": [{ "weight": 1.5, "dimensions": { "length": 20, "width": 15, "height": 10 } }]
  },
  "accounts": [{ "typeCode": "shipper", "number": "YOUR_DHL_ACCOUNT" }]
}

If you have many items, place a Loop node in ForEach mode over {{ extract.items }} and build the lineItems array, or assemble the payload first in a Transform node and pass the finished object to create-shipment. The tool returns the DHL response under {{ shipment.data }}, including the tracking number and the base64 label and customs documents.

Step 5: Email the customs paperwork to the customer

Add a Send Email node, which sends from Spojit's built-in mail service with no connection required. Set Recipients to {{ order.email }} (or {{ input.from }} if you skipped Shopify), write a Subject such as Customs documents for order {{ extract.orderNumber }}, and reference the tracking number from {{ shipment.data }} in the Body. Attach the customs document bytes that DHL returned in the shipment response. If the carrier returns the document as base64, you can feed that value straight into the Send Email attachment. Set If sending fails to Fail the workflow so a delivery problem surfaces in the execution log rather than silently passing.

Step 6: Optional pause for high-value declarations

For high-value declarations, add a Condition node before Step 4 that checks the declared value (for example, whether {{ extract.items }} sums above a threshold; compute the total in a Transform node first if you need an exact figure). Route the true branch through a Human node so a team member confirms the declared value before DHL is called. Set the Approval slots to the role that owns customs sign-off; the workflow continues only on approval and halts on rejection. This keeps automated bookings flowing while still gating the rare high-risk declaration.

Tips

  • Reuse this DHL booking logic across stores by moving Steps 4 and 5 into a Subworkflow node, then call it with the line items as Input from any order-source workflow.
  • Use get-rates on the DHL Express connector before booking if you want to surface the cost in the customer email or pick the cheapest product code.
  • Keep the Agent-mode prompt tight and always pair it with a Response Schema; structured output is what makes the DHL payload mapping deterministic.
  • Ask Miraxa to scaffold the canvas with a prompt like "Build a workflow with an Email trigger, an Agent-mode Connector to extract line items, a DHL Express create-shipment node, and a Send Email node," then fine-tune each node in the properties panel.

Common Pitfalls

  • Forgetting isCustomsDeclarable. A domestic-style payload will be rejected for an international destination, or worse, ship without customs documents. Always set it to true for cross-border shipments.
  • Mismatched currencies. The per-item price and the top-level declaredValue must use the same currency code you put in declaredValueCurrency. Carry one currency value through from the extraction step.
  • Trusting the email for the address. Order-notification emails are often truncated. Pull the ship-to address from get-order rather than parsing it out of the body.
  • External recipients blocked. If the Send Email step targets an address outside your domain, that address must be on the allowlist under Settings -> General -> Email recipients or the send fails.

Testing

Start with a single sandbox or test DHL account and one sample order email forwarded to the connected mailbox. Run the Email trigger once, confirm the Agent-mode node returns the expected items JSON in the execution log, and verify the create-shipment payload before it is sent by inspecting the node input. Use a DHL test account number first so no real label is billed, and send the customs email to your own address to confirm the attachment arrives intact. Once a few orders book cleanly end to end, point the trigger at the live folder and enable the workflow.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.