Skip to content

Commit 8632e29

Browse files
author
bird-release[bot]
committed
Release v0.12.0 (sdk-python/v0.12.0)
1 parent f5929ab commit 8632e29

19 files changed

Lines changed: 3914 additions & 1054 deletions

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 0.12.0
4+
5+
- Agent mailboxes (inbox.ai): client.mailbox, client.mailbox_receive_rule, client.mailbox_thread, client.mailbox_thread_message
6+
- Internal pipeline improvements.
7+
38
## 0.11.0
49

510
- Add the `rejected` WhatsApp message delivery status, returned when the recipient is on the workspace's suppression list.

examples/examples.gen.py

Lines changed: 142 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -337,11 +337,142 @@ async def _ex_50() -> None:
337337

338338

339339
async def _ex_51() -> None:
340+
msg = client.mailbox.compose(
341+
"mbx_01krdgeqcxet5s7t44vh8rt9mg",
342+
to=[{"address": "user@example.com"}],
343+
subject="Hello",
344+
text="Hi there",
345+
)
346+
print(msg.id, msg.thread_id)
347+
348+
349+
async def _ex_52() -> None:
350+
mailbox = client.mailbox.create(display_name="Acme Support")
351+
print(mailbox.id)
352+
353+
354+
async def _ex_53() -> None:
355+
client.mailbox.delete("mbx_01krdgeqcxet5s7t44vh8rt9mg")
356+
357+
358+
async def _ex_54() -> None:
359+
mailbox = client.mailbox.get("mbx_01krdgeqcxet5s7t44vh8rt9mg")
360+
print(mailbox.address)
361+
362+
363+
async def _ex_55() -> None:
364+
labels = client.mailbox.labels("mbx_01krdgeqcxet5s7t44vh8rt9mg")
365+
for label in labels.data:
366+
print(label.name)
367+
368+
369+
async def _ex_56() -> None:
370+
for mailbox in client.mailbox.list():
371+
print(mailbox.id, mailbox.address)
372+
373+
374+
async def _ex_57() -> None:
375+
mailbox = client.mailbox.restore("mbx_01krdgeqcxet5s7t44vh8rt9mg")
376+
print(mailbox.id)
377+
378+
379+
async def _ex_58() -> None:
380+
mailbox = client.mailbox.resume("mbx_01krdgeqcxet5s7t44vh8rt9mg")
381+
print(mailbox.id)
382+
383+
384+
async def _ex_59() -> None:
385+
stats = client.mailbox.stats("mbx_01krdgeqcxet5s7t44vh8rt9mg")
386+
print(stats.summary)
387+
388+
389+
async def _ex_60() -> None:
390+
mailbox = client.mailbox.update("mbx_01krdgeqcxet5s7t44vh8rt9mg", display_name="Billing")
391+
print(mailbox.display_name)
392+
393+
394+
async def _ex_61() -> None:
395+
rule = client.mailbox_receive_rule.create(
396+
"mbx_01krdgeqcxet5s7t44vh8rt9mg", action="block", entry="spam.example.com",
397+
)
398+
print(rule.id)
399+
400+
401+
async def _ex_62() -> None:
402+
client.mailbox_receive_rule.delete(
403+
"mbx_01krdgeqcxet5s7t44vh8rt9mg", "rrule_01krdgeqcxet5s7t44vh8rt9mg",
404+
)
405+
406+
407+
async def _ex_63() -> None:
408+
for rule in client.mailbox_receive_rule.list("mbx_01krdgeqcxet5s7t44vh8rt9mg"):
409+
print(rule.id, rule.action)
410+
411+
412+
async def _ex_64() -> None:
413+
client.mailbox_thread.delete("thr_01krdgeqcxet5s7t44vh8rt9mg")
414+
415+
416+
async def _ex_65() -> None:
417+
thread = client.mailbox_thread.get("thr_01krdgeqcxet5s7t44vh8rt9mg")
418+
print(thread.subject)
419+
420+
421+
async def _ex_66() -> None:
422+
for thread in client.mailbox_thread.list():
423+
print(thread.id, thread.subject)
424+
425+
426+
async def _ex_67() -> None:
427+
thread = client.mailbox_thread.update(
428+
"thr_01krdgeqcxet5s7t44vh8rt9mg",
429+
labels={"add": ["archive"]},
430+
)
431+
print(thread.id)
432+
433+
434+
async def _ex_68() -> None:
435+
result = client.mailbox_thread_message.attachments(
436+
"thr_01krdgeqcxet5s7t44vh8rt9mg", "msg_01krdgeqcxet5s7t44vh8rt9mg",
437+
)
438+
for attachment in result.data:
439+
print(attachment.filename, attachment.size)
440+
441+
442+
async def _ex_69() -> None:
443+
body = client.mailbox_thread_message.body(
444+
"thr_01krdgeqcxet5s7t44vh8rt9mg", "msg_01krdgeqcxet5s7t44vh8rt9mg",
445+
)
446+
print(body.html)
447+
448+
449+
async def _ex_70() -> None:
450+
message = client.mailbox_thread_message.get(
451+
"thr_01krdgeqcxet5s7t44vh8rt9mg", "msg_01krdgeqcxet5s7t44vh8rt9mg",
452+
)
453+
print(message.subject)
454+
455+
456+
async def _ex_71() -> None:
457+
for message in client.mailbox_thread_message.list("thr_01krdgeqcxet5s7t44vh8rt9mg"):
458+
print(message.id, message.subject)
459+
460+
461+
async def _ex_72() -> None:
462+
reply = client.mailbox_thread_message.reply(
463+
"thr_01krdgeqcxet5s7t44vh8rt9mg",
464+
"msg_01krdgeqcxet5s7t44vh8rt9mg",
465+
text="Thanks for reaching out!",
466+
)
467+
print(reply.id)
468+
469+
470+
async def _ex_73() -> None:
340471
for message in client.sms.list(direction="outbound"):
341472
print(message.id, message.status)
342473

343474

344-
async def _ex_52() -> None:
475+
async def _ex_74() -> None:
345476
msg = client.sms.send(
346477
to="+15551234567",
347478
text="Your verification code is 123456.",
@@ -350,54 +481,54 @@ async def _ex_52() -> None:
350481
print(msg.id, msg.status)
351482

352483

353-
async def _ex_53() -> None:
484+
async def _ex_75() -> None:
354485
client.sms.send(
355486
to="+15551234567",
356487
template="bird_otp_verification",
357488
parameters={"code": "123456"},
358489
)
359490

360491

361-
async def _ex_54() -> None:
492+
async def _ex_76() -> None:
362493
template = client.sms_templates.get("bird_otp_verification")
363494
print(template.body, template.variables)
364495

365496

366-
async def _ex_55() -> None:
497+
async def _ex_77() -> None:
367498
templates = client.sms_templates.list(scope="system")
368499
for template in templates.data:
369500
print(template.id, template.name)
370501

371502

372-
async def _ex_56() -> None:
503+
async def _ex_78() -> None:
373504
result = client.verify.verifications.check("123456", phone="+15551234567")
374505
print(result.success)
375506

376507

377-
async def _ex_57() -> None:
508+
async def _ex_79() -> None:
378509
verification = client.verify.verifications.create(phone="+15551234567")
379510
print(verification.id, verification.status)
380511

381512

382-
async def _ex_58() -> None:
513+
async def _ex_80() -> None:
383514
# Pass the RAW request body (bytes) and the request headers.
384515
event = client.webhooks.unwrap(request.body, request.headers)
385516
if event.root.type == "email.delivered":
386517
print(event.root.data.email_id)
387518

388519

389-
async def _ex_59() -> None:
520+
async def _ex_81() -> None:
390521
for message in client.whatsapp.list(status=["delivered"]):
391522
print(message.id, message.status)
392523

393524

394-
async def _ex_60() -> None:
525+
async def _ex_82() -> None:
395526
events = client.whatsapp.list_events("wam_01krdgeqcxet5s7t44vh8rt9mg")
396527
for event in events.data:
397528
print(event.type, event.occurred_at)
398529

399530

400-
async def _ex_61() -> None:
531+
async def _ex_83() -> None:
401532
msg = client.whatsapp.send(
402533
to="+31612345678",
403534
template="bird_otp",
@@ -407,7 +538,7 @@ async def _ex_61() -> None:
407538
print(msg.id, msg.status)
408539

409540

410-
async def _ex_62() -> None:
541+
async def _ex_84() -> None:
411542
templates = client.whatsapp_templates.list()
412543
for template in templates.data:
413544
print(template.name, template.status)

examples/reference/contacts.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""Example source for the generated contacts methods.
2+
3+
Each bird:snippet region is harvested for the docs site + README; the keys match
4+
the surface catalog (contacts.<leaf>). Hand-written and type-checked (pyright
5+
includes examples/); nothing regenerates over it. The override methods —
6+
contacts.update/batch/list — keep their examples inline in
7+
src/bird/resources/contacts.py, since nothing regenerates over a hand method.
8+
"""
9+
10+
from bird import Bird
11+
12+
client = Bird()
13+
14+
15+
def contacts_create() -> None:
16+
contact = client.contacts.create(email="jane@acme.com", first_name="Jane")
17+
print(contact.id, contact.email)
18+
19+
20+
def contacts_get() -> None:
21+
contact = client.contacts.get("con_01krdgeqcxet5s7t44vh8rt9mg")
22+
print(contact.email)
23+
24+
25+
def contacts_delete() -> None:
26+
client.contacts.delete("con_01krdgeqcxet5s7t44vh8rt9mg")
27+
28+
29+
def contacts_list() -> None:
30+
for contact in client.contacts.list(q="acme.com"):
31+
print(contact.id, contact.email)

examples/reference/email.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""Example source for the generated email.stats methods.
2+
3+
Each bird:snippet region is harvested for the docs site + README; the keys
4+
match the surface catalog (email.stats.<leaf>). Hand-written and type-checked
5+
(pyright includes examples/); nothing regenerates over it.
6+
"""
7+
8+
from bird import Bird
9+
10+
client = Bird()
11+
12+
def email_stats_summary() -> None:
13+
summary = client.email.stats.summary(from_="2026-05-01", to="2026-05-25")
14+
print(summary.sends_accepted, summary.delivery)
15+
16+
17+
def email_stats_daily() -> None:
18+
stats = client.email.stats.daily(from_="2026-05-01", to="2026-05-25")
19+
for point in stats.data:
20+
print(point.bucket, point.sends_accepted)
21+
22+
23+
def email_stats_hourly() -> None:
24+
stats = client.email.stats.hourly(
25+
from_="2026-05-25T00:00:00Z",
26+
to="2026-05-25T23:59:59Z",
27+
)
28+
for point in stats.data:
29+
print(point.bucket, point.delivery)
30+
31+
32+
def email_stats_byTag() -> None:
33+
stats = client.email.stats.by_tag(from_="2026-05-01", to="2026-05-25", sort="delivered")
34+
for row in stats.data:
35+
print(row)
36+
print(stats.total)
37+
38+
39+
def email_stats_byCategory() -> None:
40+
stats = client.email.stats.by_category(from_="2026-05-01", to="2026-05-25")
41+
for row in stats.data:
42+
print(row)
43+
44+
45+
def email_stats_bySendingIp() -> None:
46+
stats = client.email.stats.by_sending_ip(
47+
from_="2026-05-01", to="2026-05-25", sort="bounces.block",
48+
)
49+
for row in stats.data:
50+
print(row)
51+
52+
53+
def email_stats_bySendingDomain() -> None:
54+
stats = client.email.stats.by_sending_domain(from_="2026-05-01", to="2026-05-25")
55+
for row in stats.data:
56+
print(row)
57+
58+
59+
def email_stats_byRecipientDomain() -> None:
60+
stats = client.email.stats.by_recipient_domain(from_="2026-05-01", to="2026-05-25")
61+
for row in stats.data:
62+
print(row)
63+
64+
65+
def email_stats_byMailboxProvider() -> None:
66+
stats = client.email.stats.by_mailbox_provider(from_="2026-05-01", to="2026-05-25")
67+
for row in stats.data:
68+
print(row)
69+
70+
71+
def email_stats_byMailboxProviderRegion() -> None:
72+
stats = client.email.stats.by_mailbox_provider_region(from_="2026-05-01", to="2026-05-25")
73+
for row in stats.data:
74+
print(row)
75+
76+
77+
def email_stats_byTemplate() -> None:
78+
stats = client.email.stats.by_template(from_="2026-05-01", to="2026-05-25")
79+
for row in stats.data:
80+
print(row)
81+
82+
83+
def email_stats_byLocation() -> None:
84+
stats = client.email.stats.by_location(
85+
from_="2026-05-01", to="2026-05-25", group_by="country",
86+
)
87+
for row in stats.data:
88+
print(row)
89+
90+
91+
def email_stats_byClient() -> None:
92+
stats = client.email.stats.by_client(
93+
from_="2026-05-01", to="2026-05-25", group_by="email_client",
94+
)
95+
for row in stats.data:
96+
print(row)
97+
98+
99+
def email_stats_byBounceCode() -> None:
100+
stats = client.email.stats.by_bounce_code(from_="2026-05-01", to="2026-05-25")
101+
for row in stats.data:
102+
print(row)
103+
104+
105+
def email_stats_byComplaintType() -> None:
106+
stats = client.email.stats.by_complaint_type(from_="2026-05-01", to="2026-05-25")
107+
for row in stats.data:
108+
print(row)
109+
110+
111+
def email_stats_byBroadcast() -> None:
112+
stats = client.email.stats.by_broadcast(from_="2026-05-01", to="2026-05-25")
113+
for row in stats.data:
114+
print(row)
115+

scripts/surface_ops.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,20 @@
4848
"/v1/audiences/{audience_id}/contacts": {"get", "post"},
4949
"/v1/audiences/{audience_id}/contacts/remove": {"post"},
5050
"/v1/audiences/{audience_id}/contacts/{contact_id}": {"delete"},
51+
"/v1/email/mailboxes": {"get", "post"},
52+
"/v1/email/mailboxes/{mailbox_id}": {"delete", "get", "patch"},
53+
"/v1/email/mailboxes/{mailbox_id}/restore": {"post"},
54+
"/v1/email/mailboxes/{mailbox_id}/resume": {"post"},
55+
"/v1/email/mailboxes/{mailbox_id}/stats": {"get"},
56+
"/v1/email/mailboxes/{mailbox_id}/messages": {"post"},
57+
"/v1/email/mailboxes/{mailbox_id}/labels": {"get"},
58+
"/v1/email/mailboxes/{mailbox_id}/receive-rules": {"get", "post"},
59+
"/v1/email/mailboxes/{mailbox_id}/receive-rules/{rule_id}": {"delete"},
60+
"/v1/email/threads": {"get"},
61+
"/v1/email/threads/{thread_id}": {"delete", "get", "patch"},
62+
"/v1/email/threads/{thread_id}/messages": {"get"},
63+
"/v1/email/threads/{thread_id}/messages/{message_id}": {"get"},
64+
"/v1/email/threads/{thread_id}/messages/{message_id}/body": {"get"},
65+
"/v1/email/threads/{thread_id}/messages/{message_id}/reply": {"post"},
66+
"/v1/email/threads/{thread_id}/messages/{message_id}/attachments": {"get"},
5167
}

0 commit comments

Comments
 (0)