Automate order confirmations, pickup notifications, and loyalty updates while keeping a human in the loop on anything that touches state marketing restrictions.
Cannabis and CBD businesses operate under some of the most fragmented regulatory environments in the US. What's compliant in Colorado may be prohibited in Texas. Promotional emails require age-gated recipient lists, product claims must avoid unsubstantiated health language, and local licensing rules dictate what operational messages can say about inventory. AI agents can handle the operational email load — confirmations, pickups, loyalty points — but any send that touches promotional content or health-adjacent claims carries real legal exposure. The default posture for cannabis email automation should be gated: agents compose, humans approve before delivery.
Cannabis advertising rules vary by state and product type. An agent sending a promotional blast that's compliant in California may violate Nevada's marketing rules for the same product. Recipient jurisdiction must be checked before every promotional send.
CAN-SPAM and state cannabis regulations both require that promotional emails only reach verified adults. Sending to an unverified list isn't just a compliance gap — it can trigger state licensing action.
FTC Act enforcement has increased scrutiny of CBD health claims. Phrases like 'reduces inflammation' or 'treats anxiety' require substantiation that most operators don't have. Agents generating marketing copy must route through human review before sending.
Order confirmations and pickup notifications may reference products, quantities, or locations that are subject to local licensing conditions. Inventory references in transactional email need to align with what the license actually permits.
Medical cannabis programs often layer state privacy requirements on top of standard consumer data rules. Email systems handling patient or caregiver communications must treat recipient identity and purchase data with heightened protection.
Configure your cannabis email agent with gated_send oversight so transactional messages (order confirmations, pickup alerts) dispatch autonomously while any promotional or health-adjacent content routes to a compliance reviewer before delivery. The agent calls decide_email with a hold flag, and no send occurs until a human approves via the MultiMail dashboard or API.
Order confirmations, pickup-ready notifications, and loyalty point updates don't require human approval on every send — they follow templates that have already been reviewed. Run these flows in monitored mode so your compliance team receives notifications without becoming a bottleneck for routine transactional volume.
Give a compliance-focused agent read-only access to your outbound mailbox to scan sent emails against a regulatory checklist — checking for prohibited health claims, missing age-gate disclosures, or unsubscribe compliance — without any risk of accidental sends.
When launching a new product line or entering a new state market, use gated_all to require human approval on every outbound message until your team has validated that the templates meet the local requirements. Downgrade to gated_send once templates are reviewed.
import multimail
client = multimail.Client(api_key="mm_live_...")
def send_order_confirmation(order: dict, customer: dict) -> dict:
"cm"># Only send to states where operator holds a license
licensed_states = {"CA", "CO", "NV", "OR", "WA", "MI", "IL"}
customer_state = customer.get("state", "").upper()
if customer_state not in licensed_states:
return {"status": "skipped", "reason": "recipient_state_not_licensed"}
return client.send_email(
from_address="[email protected]",
to=customer["email"],
subject=f"Order "cm">#{order['id']} confirmed — pickup ready",
body=(
f"Hi {customer[&"cm">#039;first_name']},\n\n"
f"Your order "cm">#{order['id']} is confirmed for pickup at "
f"{order[&"cm">#039;location_name']}.\n\n"
f"Items: {&"cm">#039;, '.join(order['items'])}\n"
f"Pickup window: {order[&"cm">#039;pickup_window']}\n\n"
"This message contains no promotional content."
),
tags=["transactional", "order-confirmation"],
)Send an autonomous order confirmation only after verifying the recipient's state is in the operator's licensed delivery area. Promotional content is explicitly excluded from this flow.
import multimail
client = multimail.Client(api_key="mm_live_...")
def queue_promotional_email(campaign: dict, recipient_segment: list[str]) -> dict:
"""
Queues a promotional draft for human compliance review.
No send occurs until approved via decide_email.
"""
"cm"># Compose the draft — agent writes, human approves
draft = client.send_email(
from_address="[email protected]",
to=recipient_segment,
subject=campaign["subject"],
body=campaign["body"],
tags=["promotional", f"campaign:{campaign[&"cm">#039;id']}"],
hold=True, # gated_send: hold for human approval
metadata={
"campaign_id": campaign["id"],
"target_states": campaign["states"],
"age_verified_list": campaign["age_verified"],
},
)
# Returns message_id for the reviewer to act on
return {
"message_id": draft["message_id"],
"status": "pending_review",
"review_url": f"https://app.multimail.dev/pending/{draft[&"cm">#039;message_id']}",
}
def compliance_approve(message_id: str, reviewer_id: str) -> dict:
"""Called by the human reviewer after checking state restrictions."""
return client.decide_email(
message_id=message_id,
decision="approve",
reviewer=reviewer_id,
)An agent composes a promotional email and routes it to the list:pending queue via decide_email. A compliance reviewer must approve before delivery. Uses gated_send oversight so the hold is enforced at the API level.
import multimail
from datetime import datetime
client = multimail.Client(api_key="mm_live_...")
def send_loyalty_update(member: dict) -> dict:
if not member.get("age_verified"):
return {"status": "skipped", "reason": "age_not_verified"}
result = client.send_email(
from_address="[email protected]",
to=member["email"],
subject=f"You have {member[&"cm">#039;points']} points — here's what's available",
body=(
f"Hi {member[&"cm">#039;first_name']},\n\n"
f"Your current balance: {member[&"cm">#039;points']} points.\n"
f"Eligible rewards are available in-store at your next visit.\n\n"
"Offers are subject to local availability and licensing.\n\n"
"To stop receiving loyalty emails, reply STOP or "
"visit dispensary.multimail.dev/unsubscribe."
),
tags=["loyalty", "transactional"],
)
# Tag with age-verification audit trail
client.tag_email(
message_id=result["message_id"],
tags=[
f"age_verified:{member[&"cm">#039;age_verified_date']}",
f"state:{member[&"cm">#039;state']}",
],
)
return resultSend loyalty point balance updates while logging age-verification metadata for compliance records. Uses the tag_email method to mark messages with the recipient's verified status.
import re
import multimail
client = multimail.Client(api_key="mm_live_...")
"cm"># FTC-flagged claim patterns for CBD/cannabis
PROHIBITED_PATTERNS = [
r"\bcures\b",
r"\btreats\b",
r"\bheals\b",
r"FDA[- ]approved",
r"clinically proven",
r"reduces (?:anxiety|inflammation|pain)",
r"medical(?:ally)? (?:proven|tested|verified)",
]
def scan_sent_folder_for_violations(mailbox: str, days: int = 7) -> list[dict]:
"""Read-only scan — no mutations, no sends."""
messages = client.check_inbox(
mailbox=mailbox,
folder="sent",
since_days=days,
)
violations = []
for msg_summary in messages["emails"]:
msg = client.read_email(message_id=msg_summary["message_id"])
body = msg["body"].lower()
for pattern in PROHIBITED_PATTERNS:
if re.search(pattern, body, re.IGNORECASE):
violations.append({
"message_id": msg["message_id"],
"subject": msg["subject"],
"sent_at": msg["date"],
"matched_pattern": pattern,
})
break
return violationsAgent reads sent emails and flags messages containing prohibited health claim patterns. Uses check_inbox and read_email in read_only mode — no sends, no mutations.
| Regulation | Requirement | How MultiMail helps |
|---|---|---|
| State Cannabis Regulations | Promotional emails must comply with the cannabis advertising rules of each recipient's state — which differ on permitted health claims, required disclosures, and what product types can be advertised via email. | The gated_send oversight mode holds all promotional sends in a review queue. Recipients can be tagged by state, and compliance reviewers see the full recipient list before approving. The decide_email endpoint lets reviewers approve, reject, or edit before delivery. |
| FTC Act | Health and wellness claims in CBD marketing must be substantiated. Unsubstantiated claims like 'reduces anxiety' or 'anti-inflammatory' expose operators to FTC enforcement action. | Agents composing marketing copy can be configured to hold any message containing flagged health claim patterns. The read_only scanning pattern lets a compliance agent audit sent mail for violations without any mutation risk. |
| CAN-SPAM | All commercial email must include a valid physical address, a functioning unsubscribe mechanism, and accurate header information. Cannabis operators must meet these baseline requirements regardless of state law. | MultiMail enforces CAN-SPAM headers at the API level. Unsubscribe events are tracked and suppressed automatically — agents querying check_inbox will not see suppressed recipients in future send targets. |
| Age Verification Requirements | Most state cannabis programs require that promotional email recipients have been age-verified (21+ for recreational, varies for medical). Sending to an unverified list can constitute a licensing violation. | Recipient metadata — including age verification status and date — can be stored as tags on outbound messages via tag_email, creating an audit trail that maps each send to a verified recipient record. Agents can check this metadata before composing. |
| State Patient Privacy Requirements | Medical cannabis programs in states like California, New York, and Florida impose privacy protections on patient purchase records and communications that go beyond standard consumer data rules. | MultiMail isolates medical and recreational mailboxes at the namespace level. Patient-facing mailboxes can be scoped to read_only or gated_all to prevent autonomous sends, reducing the risk of a privacy violation from an agent acting without appropriate authorization. |
Email infrastructure built for AI agents. Verifiable identity, graduated oversight, and a 50-tool MCP server. Formally verified in Lean 4.