Simple, dependency-light PHP helper around JMAP for sending, reading, and managing email.
The primary entry point is $mailer->sendMail(...). It creates a draft and then submits it via JMAP.
<?php
require __DIR__ . '/mailer.php';
$mailer = new JmapMailer('https://your-jmap-endpoint/jmap', 'YOUR_JMAP_TOKEN');
$mailer->sendMail(
'to@example.com', // $toEmail
'Recipient Name', // $toName (nullable)
'Hello from JMAP', // $subject
'<p>Hi there 👋<br/>This was sent via JMAP.</p>', // $html
null, // $fromEmail (optional; resolved from Identity if null)
null // $fromName (optional; resolved from Identity if null)
);Notes:
- The
Fromaddress is resolved from your JMAP identities if you do not provide one. - The message is first created in the Drafts mailbox, then submitted. If a Sent mailbox is available, the draft is moved there after submission.
This library is a single file. Include it directly:
require __DIR__ . '/mailer.php';Requirements:
- PHP 7.4+ with
ext-curl - A JMAP-compatible server and an access token
new JmapMailer(string $apiBase, string $token)- apiBase: Your JMAP base endpoint. Passing either the API root or
.../jmapis fine; the session discovery will determine the correct API URL. - token: Bearer token used for Authorization.
-
sendMail(...) : void
- High-level helper that creates a draft and immediately submits it.
- Parameters:
(string $toEmail, ?string $toName, string $subject, string $html, ?string $fromEmail = null, ?string $fromName = null)
-
createDraft(...) : string
- Creates a JMAP Email in the Drafts mailbox and returns the new Email id.
- Same parameters as
sendMail.
-
editDraft(string $emailId, ?string $toEmail = null, ?string $toName = null, ?string $subject = null, ?string $html = null, ?string $fromEmail = null, ?string $fromName = null) : string
- Reads an existing draft, merges provided fields, deletes the original, and creates a new draft. Returns the new Email id.
-
sendDraft(string $draftEmailId) : void
- Submits an existing draft via
EmailSubmission/set. If a Sent mailbox exists, moves the message there.
- Submits an existing draft via
-
getMailboxes(?array $properties = null) : array
- Returns a simplified list of mailboxes (id, name, role, counts, etc.).
-
createMailbox(string $name, ?string $parentId = null) : array
- Creates a mailbox and returns the created mailbox object (id, name, ...).
-
updateMailbox(string $mailboxId, string $newName) : void
- Renames an existing mailbox.
-
deleteMailbox(string $mailboxId, bool $removeEmails = false) : void
- Destroys a mailbox. Optionally also removes contained emails.
-
getEmailsInMailbox(string $mailboxId, int $limit = 50, int $position = 0) : array
- Queries and returns a list of messages in a mailbox (from/to/subject/flags/preview, etc.).
-
getEmail(string $emailId) : array
- Returns detailed information for a message including extracted
textBodyandhtmlBody.
- Returns detailed information for a message including extracted
-
moveEmail(string $emailId, string $targetMailboxId) : void
- Moves an email to the target mailbox (sets
mailboxIdsto that mailbox only).
- Moves an email to the target mailbox (sets
-
copyEmail(string $emailId, string $targetMailboxId) : void
- Adds the target mailbox to
mailboxIds, effectively copying while keeping it in existing mailboxes.
- Adds the target mailbox to
-
deleteEmail(string $emailId) : void
- Destroys an email.
$mailer = new JmapMailer('https://your-jmap-endpoint/jmap', 'YOUR_JMAP_TOKEN');
$mailboxes = $mailer->getMailboxes();
foreach ($mailboxes as $mb) {
echo $mb['id'] . ' ' . $mb['name'] . ' (' . ($mb['role'] ?? '-') . ")\n";
}$inboxId = 'MAILBOX_ID';
$emails = $mailer->getEmailsInMailbox($inboxId, 20);
foreach ($emails as $e) {
echo '[' . ($e['isUnread'] ? 'UNREAD' : 'READ') . '] ' . $e['subject'] . "\n";
}// Create
$draftId = $mailer->createDraft('to@example.com', null, 'Draft subject', '<p>Body</p>');
// Edit (e.g., change subject and body)
$draftId = $mailer->editDraft($draftId, null, null, 'Updated subject', '<p>Updated body</p>');
// Send
$mailer->sendDraft($draftId);- The library discovers the JMAP session and capabilities automatically and selects identities when sending.
- If you omit
fromEmail/fromName, the default Identity from your JMAP account is used when available. - Drafts/Sent mailbox detection uses mailbox roles (
drafts,sent). If these folders are not present, draft creation or post-send moving may be impacted. - Errors are thrown as
\RuntimeExceptionwith detailed messages when JMAP reports errors.
See LICENSE.