Usage¶
The main path is short: create a client, send a message, handle typed errors.
Send a message¶
Create a client from the default configuration.
from macpymessenger import Configuration, IMessageClient
from macpymessenger.exceptions import MessageSendError
client = IMessageClient(Configuration())
Call send() with a recipient and a message.
try:
client.send("+15555555555", "Hello from macpymessenger!")
except MessageSendError as error:
print(f"Delivery failed: {error}")
send() returns None when delivery succeeds.
Handle send errors¶
The client raises typed exceptions instead of returning status flags.
MessageSendErrormeans delivery failed or AppleScript could not run.InvalidDelayTypeErrormeansdelay_secondswas not anint.boolis not accepted.NegativeDelayErrormeansdelay_secondswas less than zero.
Delay a message¶
Pass delay_seconds to wait before sending.
client.send("+15555555555", "See you in a minute.", delay_seconds=60)
The bundled AppleScript waits, then sends. If delivery fails, osascript exits non-zero and the client raises MessageSendError.
Create a template¶
A template is a callable that returns a Python 3.14 t-string.
client.create_template(
"greeting",
lambda name: t"Hello, {name}! Welcome to macpymessenger.",
)
Jinja2 is not used. There is no templates/ directory.
Send a template¶
Pass the template identifier and a context dictionary.
client.send_template("+15555555555", "greeting", {"name": "Ada"})
This renders the template and calls send().
You can also delay a templated message:
client.send_template(
"+15555555555",
"greeting",
{"name": "Ada"},
delay_seconds=30,
)
Update and delete templates¶
Use the same identifier when you want to replace a template.
client.update_template("greeting", lambda name: t"Hi {name}, welcome back.")
client.delete_template("greeting")
Missing identifiers raise TemplateNotFoundError. Duplicate identifiers raise TemplateAlreadyExistsError.
Keep template values as strings¶
Every interpolation must resolve to str. !s, !r, and !a
conversions and standard format specs are applied after the type check:
client.create_template("quoted", lambda name: t"Hello, {name!r:>10}!")
client.create_template("status", lambda name, status: t"Hi {name}. Status: {status}.")
client.send_template("+15555555555", "status", {"name": "Ada", "status": "ready"})
If status is an int or another non-string value, rendering raises TemplateTypeError.
The callable receives the context as keyword arguments, so missing values are regular Python call errors.
List all templates¶
Get a dictionary of registered template callables:
factories = manager.list_templates()
for identifier, factory in factories.items():
print(f"{identifier}: {factory.__name__}")
The returned dictionary is a shallow copy, so modifying it does not affect the manager.
Use TemplateManager directly¶
Use TemplateManager for rendering without a client.
from macpymessenger import TemplateManager
manager = TemplateManager()
manager.create_template("welcome", lambda name: t"Welcome, {name}.")
rendered = manager.compose_template("welcome", {"name": "Ada"})
print(rendered.content)
compose_template() returns RenderedTemplate. render_template() returns only the rendered string.
Send to multiple recipients¶
send_bulk() sends one message to many recipients.
numbers = ["+15555555555", "+15555555556", "+15555555557"]
successful, failed = client.send_bulk(numbers, "Reminder: meeting at 10 AM.")
send_bulk() returns (successful, failed).
successfulcontains recipients wheresend()completed.failedcontains recipients whereMessageSendErrorwas raised.
Use the failed list to retry or log the result:
if failed:
print(f"Could not send to: {failed}")
Experimental stubs¶
Two methods are not implemented yet:
get_chat_history(phone_number, limit=10)send_with_attachment(phone_number, message, attachment_path)
Both always raise NotImplementedError.
client.get_chat_history("+15555555555") # raises NotImplementedError
Do not use them in production yet.