@aglyn/plugins-outreach

中文文档
1.19.0发布于 2026/11/07Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 9627

Sequences: one-to-one, multi-step email sequences a rep sends from their own connected mailbox, logged on the CRM's records. A sequence enrolls a contact or a lead (AGL-3234): an enrollment names which record the person is, a lead is judged and merged as

原始使用文档
文档目录5 节
  1. Install
  2. Mailboxes
  3. The engine
  4. The sending runtime
  5. License

@aglyn/plugins-outreach

Sequences: one-to-one, multi-step email sequences a rep sends from their own connected mailbox, logged on the CRM's records. A sequence enrolls a contact or a lead (AGL-3234): an enrollment names which record the person is, a lead is judged and merged as the contact it would be, and when the lead converts its enrollment follows it to the contact through the core's lead-conversion seam.

Published to npm from the Aglyn monorepo. Versions follow semantic versioning.

Install

npm install @aglyn/plugins-outreach

A plugin is loaded through Aglyn's plugin manager (@aglyn/aglyn) by the console and the tenant runtime; it is not a standalone library.

The name people read is Sequences. The lib, the package, the release flag, the entitlement, the permission key, the collections and the API prefix stay outreach: they are stored vocabulary and live URLs, and no reader sees them.

Two halves, like the CRM plugin:

  • Console (registerOutreachConsole, client barrel): the organization-level Sequences hub at /[orgSlug]/outreach/<section>, declared through ConsoleExtension.orgNavItems, behind release_outreach, the features.outreach entitlement and the outreach.use permission. Behind the same gates, one widget in a zone the CRM hosts: Reply in thread from the mailbox in a contact's or a lead's header, before Send email (crmRecordEmailActions, AGL-4020).
  • Console API (registerOutreachConsoleApi, @aglyn/plugins-outreach/server): handlers under the outreach/ prefix, served by the console's /api/[...pluginApi] dispatcher.

Two more entries, neither of them loaded by the tenant runtime:

  • Console-only server declarations (registerOutreachConsoleServerDeclarations, @aglyn/plugins-outreach/declarations.console-server): the workspace and account erasers, registered at the console's boot. They revoke a rep's Google grant with OUTREACH_TOKEN_KEY, which only the console holds.
  • Subprocessors (outreachSubprocessors, @aglyn/plugins-outreach/subprocessors): the third-party hosts the plugin's code names, which the manifest generator writes into the console's subprocessor inventory.

The document model shared by both halves is src/lib/model/outreach.types.ts. Every outreach* collection is written by the server alone.

Mailboxes

src/lib/mailboxes and src/lib/transport connect a rep's own Google or Microsoft 365 mailbox and talk to it:

moduledoes
mailboxes/mailbox-routesconnect (signed single-use state, PKCE, OpenID nonce), settings, pause, test and disconnect
mailboxes/oauth-statethe signed state and its pending record under orgs/{orgId}/outreachOAuthStates
mailboxes/mailbox-credentialsthe refresh token sealed with the shared secret box, in outreachMailboxCredentials
mailboxes/mailbox-transportopens a mailbox's client for its provider, and marks one reconnect-required
mailboxes/mailbox-erasurewhat a workspace or account erasure revokes and deletes
transport/mail-clientthe provider seam the runtime reaches a mailbox through, and the structured search
transport/gmail-clientthe fetch-based Gmail API client: send, full and metadata thread reads, search, send-as
transport/graph-clientthe Microsoft Graph client: a step sent as a draft from its own MIME, conversation and message reads, the windowed search
transport/microsoft-oauthMicrosoft's identity platform: consent address, code exchange, refresh, ID token
transport/mime-messagea raw MIME message read into the Gmail API shape the classifier takes
transport/send-messagethe one door a send goes through, including the engine's composed email
transport/rfc5322the plain-text RFC 5322 writer

OUTREACH_TOKEN_KEY, GOOGLE_OUTREACH_CLIENT_ID, GOOGLE_OUTREACH_CLIENT_SECRET, MICROSOFT_OUTREACH_CLIENT_ID, MICROSOFT_OUTREACH_CLIENT_SECRET and MICROSOFT_OUTREACH_TENANT are read by mailboxes/outreach-config alone, and outreach-credential-isolation.spec.ts holds that no tenant file reaches it.

The engine

src/lib/engine is every decision the sending runtime makes, as pure functions with no I/O, exported from the package root:

moduledecides
sequence-validationwhat a sequence may be: 8 steps, 4 emails, 1–30 business days, subjects, bodies, windows, countries; and what activation refuses on
gateswho may be emailed, over a contact as stored and the results of the runtime's lookups, with a sentence per block
schedulewhen a step comes due: business days in the mailbox's zone, clamped into the window, with jitter
sending-capacitythe daily cap and warm-up ramp, the per-run allowance, and which due enrollments go first
enrollment-statethe enrollment state machine, the new enrollment document, and what a completed step writes
composethe email a step sends: merge fields, the mandatory footer, threading, unsubscribe headers
thread-messagethe classifier's message shape, and the adapter from a Gmail API message
delivery-status, opt-out-intent, thread-classificationwhat came back: bounces, automatic replies, replies and opt-outs
mailbox-healthwhen a mailbox pauses itself
mailbox-noticethe email a mailbox's owner gets when it pauses itself or needs reconnecting
gateway-blockwhether a hard bounce is the recipient domain's gateway refusing the sender, rather than one unknown address
do-not-contact-domainhow a domain on the do-not-contact list is spelled
manual-replyanswering a person who wrote back (AGL-4020): what the enrollment keeps of their messages, the in-thread answer (Re:, In-Reply-To, References, their message quoted) and what still refuses it

engine/do-not-contact derives the do-not-contact document id with node:crypto, so it is not in the barrel: import @aglyn/plugins-outreach/engine/do-not-contact from server code.

The sending runtime

src/lib/runtime runs the engine against real mailboxes, in the console alone — each run opens a rep's sealed grant:

moduledoes
runtime/send-joboutreach-send: due enrollments claimed in a transaction that reserves the mailbox's day, gates asked again, the email composed — with the List-Unsubscribe header when the sequence turns it on (AGL-3296), and its links' outreachLinks documents written first when it tracks clicks (AGL-3297) — and sent, the step recorded and filed on the contact's timeline; task steps file the rep's task
runtime/sync-joboutreach-sync: replies, out-of-office answers, opt-outs and bounces read with format=full and classified by the engine; what the person wrote kept on the enrollment (AGL-4020); the mailbox's health evidence and its automatic pause
routes/reply-routes, components/reply-dialogReply in thread (AGL-4020): outreach/enrollments/thread reads what the person wrote — from the mailbox, for a reply synced before replies were kept — and outreach/enrollments/reply sends a member's answer from the enrollment's mailbox in the same thread, kept as a manual_reply step record and on the CRM timeline, counted on health.daily.<day>.manualReplies and never against the cap; on a sequence that tracks clicks its links go out as short links, each a click of the person's and never the sequence's (AGL-4022)
runtime/unsubscribe-link, runtime/unsubscribe-routethe signed one-click link (GET and RFC 8058 POST /api/outreach/unsubscribe), a recipient link that outlives a paused rollout, and the +unsubscribe mailto
runtime/click-link, runtime/click-routeclick tracking: the short link every send carries (GET /api/outreach/l/<id>, resolved through the top-level outreachLinks document, AGL-3297) and the signed GET /api/outreach/click?t=… link older emails carry; both recipient links, redirect first, then the click counted once per person with scanners kept apart; on the mailbox domain's verified links. host as https://links.<domain>/<id> (AGL-3306), which the console middleware rewrites to the same route
routes/link-domain-routes, components/link-domains-cardSequences → Mailboxes → Link domains (AGL-3306): outreach/link-domains lists each mailbox domain's links. host and sets one up, checks it or removes it through @aglyn/tenant-data-admin/server/tracking-hosts — the domain driver attaches it, an HTTPS probe verifies it; set-up and removal are an owner's or admin's
runtime/enrollment-eventsstatus changes as the engine's events, and an opt-out recorded on every list
runtime/mailbox-noticesthe owner told, once, when a mailbox pauses itself or needs reconnecting
runtime/timelinethe contact's timeline, through the core's record-timeline seam
runtime/person-erasurethe enrollments a person erasure deletes, and the do-not-contact entry it keeps

Both jobs are declared on the core's plugin-console-crons from the console-only declarations, which run them every fifteen minutes from /api/admin/plugin-crons and give each a row on /api/health/crons. Their dependencies are runtime/runtime-deps; runtime/fixtures/fake-gmail is the in-memory mailbox the emulator specs run them against.

License

Apache-2.0. Source: https://github.com/aglyn/aglyn/tree/main/libs/plugins/outreach

版本与发布记录

@aglyn/plugins-outreach 共发布 162 个版本,首次发布于 2026/09/21;过去 12 个月发布了 162 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.19.0latest2026/11/07今天
1.18.02026/11/07今天
1.17.02026/11/07今天
1.16.02026/11/07今天
1.15.22026/11/061 天前
1.15.12026/11/061 天前

其他发布通道:beta → 1.0.0-beta.296。

关于 @aglyn/plugins-outreach 的常见问题

@aglyn/plugins-outreach 是什么?

Sequences: one-to-one, multi-step email sequences a rep sends from their own connected mailbox, logged on the CRM's records. A sequence enrolls a contact or a lead (AGL-3234): an enrollment names which record the person is, a lead is judged and merged as

如何安装 @aglyn/plugins-outreach?

在项目目录运行 npm install @aglyn/plugins-outreach,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:next(^16.3.3)、react(^19.2.8)、firebase(^13.0.0)、@mui/material(^9.3.1)、firebase-admin(^14.3.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@aglyn/plugins-outreach 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@aglyn/plugins-outreach 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@aglyn/plugins-outreach 可以商用吗?

@aglyn/plugins-outreach 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@aglyn/plugins-outreach 的下载量有多少?

根据 npm 官方下载统计,@aglyn/plugins-outreach 在 2026/10/05 – 2026/11/03 这 30 天内被下载 9,627 次,日均约 321 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@aglyn/plugins-outreach 还在维护吗?

最新版本 1.19.0 发布于 2026/11/07(今天);至今共发布 162 个版本,其中过去 12 个月发布了 162 个;首次发布于 2026/09/21。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。