Skip to content

Releases

0.2.4

Choose a tag to compare

@goldnead goldnead released this 17 Oct 18:25

Changed

  • Settings: the addon now declares settingsNavParent() ([section, name] of its own Control Panel navigation entry). With statamic-brand-context 1.16 or newer its settings show as the sub-item "Einstellungen" under that entry; addons without a navigation of their own share one "Addon-Suite" page under Settings. Older brand-context versions ignore the method and keep the previous layout.
  • Settings: the sub-item carries the same name as the navigation entry, also when the entry shows a counter.

Upgrading

  • No migration, no new config key.

0.2.3

Choose a tag to compare

@goldnead goldnead released this 30 Sep 13:20

Added

  • [new] inbox:summary for agents over SSH: per mailbox (name, address, brand) the numbers new,
    open and of those unread, waiting longer than --wartet days (default 7), snoozed and snoozed
    until today, plus fetch problems (last_error, folder errors, messages given up on). --json
    for a fixed JSON shape, --details for the first five conversations behind each number
    (subject, other side, age; never a body), --brand to narrow to one brand. Read only: no
    write, no event, no log line, and unread stays as it was. See "For agents / CLI" in the
    README.

Changed

  • The tab logic moved from ConversationsController into Support\ConversationQuery, which the
    listing, the unread badge in the nav and inbox:summary now share. The tab counts and the
    badge are unchanged.

0.2.2

Choose a tag to compare

@goldnead goldnead released this 27 Sep 03:33

Signatures, and the mails your website sends through the mailbox no longer count as yours.

Added

  • [new] Signatures. Several per mailbox, set up in the new "Signaturen" tab of the mailbox form: a
    name, plain text (line breaks stay, web addresses become links), one of them the default, and
    optionally LeadHub tags. For a contact with one of those tags that signature is preselected; the
    first one from the top wins, without a match the default. Placeholders: {{ sender.name }} and
    {{ mailbox.email }}. The reply form has a picker with a preview underneath, "Keine" included.
    The signature goes under the text and above the quote, after -- in the text part.
  • [new] Replies are sent with an HTML part next to the text: everything escaped, links clickable, the
    quote as a blockquote.
  • [new] With a signature chosen, the AI draft ends without a closing line carrying a name.

Changed

  • The Migadu and All-Inkl presets send over port 587 with STARTTLS instead of 465. Many hosts block outbound
    465, and the connection test then times out. Sites that published config/inbox.php keep their
    own value; existing mailboxes keep their saved port.
  • Mails the website sends through the mailbox are system mails. Order and booking
    confirmations, invoices, access mails in Sent no longer make a conversation relevant, no longer
    set it to "waiting", and no longer make the recipient a known correspondent. On their own they
    open no conversation (skip reason system); inside one that exists anyway they show folded and
    marked "automatisch". Recognised by Auto-Submitted, X-Auto-Response-Suppress or X-Suite-*
    headers; otherwise never when a person clearly wrote it (a reply from the inbox, Gmail's
    webmail, a mail program in User-Agent/X-Mailer such as Roundcube, Thunderbird, Apple Mail or
    Outlook, or a mail that answers another); then by subject (inbox.system_mail.subjects, by
    default the subjects the suite sends, in both forms of address), or by a Symfony/Laravel
    Message-ID together with a sender name from inbox.system_mail.senders. The Message-ID alone
    never decides: Roundcube builds the same shape.
  • info+anything@domain is one of your own addresses when info@domain is the mailbox address
    or an alias: mail to or from it makes no conversation.
  • inbox:reclassify applies both to what is stored: conversations made only of system mails or
    only of mail to your own (plus) addresses are deleted with skip records, system mails in the
    others are marked. It prints "only system mails" and "marked as automatic".

Fixed

  • [fix] A reply sent from the inbox gets its IMAP UID once the fetch meets it in Sent, so
    inbox:reclassify can read its headers later.

Security

  • The clean-up that deletes conversations (hiding a sender, inbox:reclassify) took a reason
    given as text for a callable when the text named a PHP function. In 0.2.1 only the fixed
    reasons self and blocked reached it, never outside input, so it was not reachable; the
    reason system of this release would have been. A reason is now only ever called when it is a
    closure.

Upgrading

  • php artisan migrate (adds inbox_mailboxes.signatures and inbox_messages.automatic), then
    php artisan inbox:reclassify --dry-run, then without --dry-run.

0.2.1

Choose a tag to compare

@goldnead goldnead released this 25 Sep 20:17

The filter could hide or delete real leads. Fixed, with a way to get back what 0.2.0 skipped.

Fixed

  • [fix] Hiding a sender or domain deletes first contacts only. Conversations you answered, with a
    LeadHub contact, or taken over stay, your own sent mails in them included. Hiding works only from
    a conversation in "Neu", and the dialog says beforehand how many conversations will be deleted.
    A contact, someone you have written to before, or a reply in an existing conversation now also
    gets through a hidden sender or domain.
  • [fix] Sent is read before INBOX. A reply that arrived in INBOX in the same fetch as your mail found
    no thread yet and could be taken for bulk mail (an out-of-office answer, a ticket system).
    Someone you have written to before is now an exception from the bulk filter as well.
  • [fix] Contact forms and booking tools. A mail from noreply@ with a person in Reply-To is that
    person: they become the other side of the conversation, the exceptions apply to them, and the
    no-reply rule does not fire.
  • [fix] Skip records keep less. The Message-ID only as a SHA-256 hash, the sender only for hidden
    senders (where removing the rule needs it). A migration clears the sender of the others.
  • [fix] Removing a hidden sender needs reply inbox, like hiding it; before, it needed
    manage inbox mailboxes.
  • [fix] inbox:reclassify takes a conversation out of "Neu" once it has become relevant, applies
    relevance even when headers cannot be read (archived mail), and reads headers stored by 0.2.0
    again because they lack Reply-To.
  • [fix] A conversation that starts with your reply is titled without Re:.

Added

  • [new] inbox:reclassify --reconsider-skipped [--dry-run] looks at every skip record again (except
    hidden senders): headers by PEEK at the recorded folder and UID, or, when the UID is gone, a
    search by Message-ID in INBOX and All Mail. What no longer counts as bulk mail is imported; the
    records left are hashed.

Upgrading

  • php artisan migrate, then php artisan inbox:reclassify --reconsider-skipped --dry-run, then
    without --dry-run, then php artisan inbox:reclassify --dry-run to check nothing is left.

0.2.0

Choose a tag to compare

@goldnead goldnead released this 25 Sep 18:57

Only relevant mail. The inbox is for conversations with leads and customers; newsletters and
invoices stay in your mail program.

Added

  • [new] Bulk mail is not taken over. A mail with List-Unsubscribe, List-Id or List-Post,
    Precedence: bulk/list/junk, Auto-Submitted (other than no), typical mailing-service headers
    (Feedback-ID, X-Campaign, X-Mailchimp-*, X-SES-Outgoing, X-MC-User and more, extendable
    via inbox.filter.bulk_headers), a no-reply sender or an empty Return-Path (bounces) is not
    stored at all. Only a skip record is kept (Message-ID, folder, UID, reason), so it is not fetched
    twice. A LeadHub contact and a reply in an existing conversation always come through. Sent mail
    to more than ten people or by Bcc list counts as a circular and is skipped too. Switch per
    mailbox: "Massenmails überspringen", on by default.
  • [new] First contacts in their own tab "Neu". A conversation is relevant when the other side is a
    LeadHub contact, when you answered or started it, or when you have written to that address from
    this mailbox before. Everything else is filed as new: shown only in "Neu", with its own count,
    not in the menu badge. Actions there: "Übernehmen", "Kontakt anlegen", "Absender ausblenden",
    "Domain ausblenden". A reply takes a conversation out of "Neu" by itself.
  • [new] Hidden senders and domains. Hiding deletes the existing conversations in Statamic
    (attachments included) and keeps future mail out; the mails stay in Gmail or your mailbox.
    Freemail domains (gmail.com, gmx.de, web.de and others) can only be hidden sender by sender. The
    mailbox page lists the rules with "Entfernen".
  • [new] Own addresses. Aliases per mailbox; mail between your own addresses makes no conversation.
  • [new] inbox:reclassify {--mailbox=} {--dry-run} applies the filter to mail imported before: reads the
    headers again over IMAP (headers only, PEEK, nothing is marked read), deletes bulk and
    to-yourself conversations with their files, files unknown people under "Neu". Always run
    --dry-run first.
  • [new] The mailbox page shows the bulk mail skipped in the last 30 days.
  • [new] New messages store the headers the filter decides on (filter_headers), so a rule change can be
    applied again without asking the server.

Changed

  • A first contact from someone unknown now arrives as new, not open.

Fixed

  • [fix] The mailbox form now saves the sender name ("Absendername"); since 0.1.0 it was shown but not
    sent.

Upgrading

  • Run php artisan migrate, then php artisan inbox:reclassify --dry-run and, when the numbers
    look right, php artisan inbox:reclassify.

0.1.1

Choose a tag to compare

@goldnead goldnead released this 25 Sep 17:48

Fixed

  • [fix] The addon list no longer calls the addon "Postfach-Einstellungen". The settings entry gets its name from settingsTitle() (brand-context 1.15), not from a global translation of the addon name "Inbox". With an older brand-context the entry reads "Inbox".

0.1.0

Choose a tag to compare

@goldnead goldnead released this 25 Sep 14:43

First release.

  • Control Panel: the inbox as core's Listing (tabs Offen, Wartet, Erledigt, Geschlummert, search,
    mailbox filter, unread dot, failed sends), fetch problems per mailbox above it, an empty state
    that leads to connecting a mailbox.
  • Conversation screen: thread with older messages and quoted text folded, HTML in a sandboxed
    frame without scripts, remote images only on click, inline images and attachments through the
    permission-checked route, LeadHub contact card or "Kontakt anlegen", status and snooze, reply
    form with template and AI draft that only fill the text.
  • Mailbox screens: list, create and edit with provider presets, write-only password that is asked
    for again when server, port or login change, connection test before or after saving.
  • German translations (lang/de.json), scripts/setup-playground.sh with seed data from the
    IMAP fake.
  • Package skeleton: service provider, per-brand settings through brand-context, permissions
    view inbox, reply inbox, manage inbox mailboxes.
  • Fetching over IMAP (directorytree/imapengine): INBOX and Sent, UID cursor per folder, first run
    from import_since (90 days), dedupe by Message-ID per mailbox, inbox:fetch every minute with
    a lock per mailbox, each mailbox inside its brand.
  • Threading by In-Reply-To, References, then counterpart plus normalised subject within 30 days.
  • Parsing with zbateson/mail-mime-parser, HTML through symfony/html-sanitizer with remote images
    held back (data-inbox-src), quoted replies stripped (own marker, then email-reply-parser).
  • Replies over the mailbox's own SMTP with Message-ID, In-Reply-To and References, APPEND to Sent
    except on Gmail, queued, failures kept on the message (send_error).
  • Suppression: hard bounce, complaint and invalid address block a reply; fail-closed.
  • LeadHub: contact linking (never creating), timeline entries deduped by inbox:{message_id}.
  • AI draft (Claude Messages API, ANTHROPIC_API_KEY), templates from email-templates, activity
    producer and an automations trigger; all optional and detected at runtime.
  • Host guard against private, loopback and link-local IMAP/SMTP hosts.
  • CP JSON endpoints and Inertia pages (inbox::…); the Vue screens follow.
  • Hardening after review: a message that cannot be stored no longer freezes a mailbox (ledger
    inbox_fetch_failures, three attempts, then given up visibly); overlong fields are cut, overlong
    Message-IDs indexed by hash; errors per folder (folder_errors) apart from a broken mailbox;
    UIDVALIDITY per folder; future Date headers clamped; srcset and <source> blocked as remote
    images; cid: images mapped to the attachment route; APPEND failures kept as filed_error;
    password required again when host, port or login change (also for the connection test);
    Gmail and Sent folder re-detected on a host change; contact links checked against LeadHub.
  • Nav item "Postfach" with the unread count, "E-Mails" panel on the LeadHub contact, and
    "Kontakt anlegen" from a conversation. The unused default_mailbox setting is gone.
  • AI drafts default to claude-sonnet-5.