Email workflow integrations and SDKs
Explore SendRepute APIs and integrations for email analysis, separately paid AI rewrites and design tools. Central analysis, rewrite and builder endpoints do not send email; deliberately enabled Campaigns delivery and certain provider adapters can send using your configured provider. No result guarantees inbox placement.
The Node.js package is available on npm. Other integrations can be downloaded here or installed from a verified public GitHub repository. Choose an integration, follow its guide, and review permissions, current pricing, and failure settings before enabling it.
Keep your current email workflow. These central API examples only analyze, rewrite or build content; they never send email. Separately, deliberately enabled Campaigns delivery and certain provider adapters can send through your configured provider. Choose a tool for its installation, configuration, examples and operating limits. Examples do not run on this page; review paid operations and sending actions separately.
WordPress plugin
0.2.0
Requires WordPress 5.7+, PHP 7.4+ and OpenSSL. Upload the ZIP through Plugins > Add New > Upload Plugin, then open Settings > SendRepute. Configure each site's token and paid-analysis consent separately. Installed lifecycle evidence covers WordPress 6.8.3 with WooCommerce 10.4.3; separate SMTP-plugin evidence covers WordPress 7.1.2 with WP Mail SMTP 4.9.0 and FluentSMTP 2.4.0.
Checks messages through pre_wp_mail without replacing SMTP or rewriting messages. Advisory mode allows delivery; blocking mode applies a probability threshold. API failure policy is configured separately. Plugins that bypass wp_mail are not covered; later transport changes are not analyzed. Blocking does not queue messages.
Analysis is disabled by default. Configure a scoped customer token, run the non-paid connection check, review pricing and explicitly consent before enabling paid analysis. Manual AI actions require separate confirmation.
Download WordPress ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Run these commands from the WordPress directory with WP-CLI available, or upload the downloaded ZIP through Plugins > Add New > Upload Plugin and activate it. Open Settings > SendRepute. Configure and activate each site separately on multisite. Keep a supported WordPress/PHP combination; a minimum version is not a recommendation to run end-of-life software.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-wp.zip
wp plugin install ./sendrepute-wp.zip --activate
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-wordpress.git
cd sendrepute-wordpress
python3 package.py
2. Configure securely
Create a server-side customer token with classify, account:read and catalog:read scopes, expiry and spend caps. Enter it in settings or load SENDREPUTE_API_TOKEN from your server secret store as shown. Stored tokens use authenticated encryption with WordPress salts and OpenSSL; re-enter them after salt rotation. Run the non-paid connection check, review classification pricing, then explicitly enable automatic analysis. Set advisory/blocking mode, threshold and independent fail-open/fail-closed policy.
// wp-config.php — optional server-secret alternative to settings storage.
$sendreputeToken = getenv('SENDREPUTE_API_TOKEN');
if (is_string($sendreputeToken) && $sendreputeToken !== '') {
define('SENDREPUTE_API_TOKEN', $sendreputeToken);
}
3. Use it deliberately
The function below uses normal wp_mail and sends only when your application calls it. With paid analysis enabled, the plugin analyzes at pre_wp_mail and then permits or blocks the existing transport. Supply your own authorized recipient; test against a non-relaying local mail sink first. A false result means the caller must handle the rejected send—it is not queued.
// Call deliberately: this sends through your existing WordPress transport.
function sendrepute_reviewed_message($recipient) {
return wp_mail(
$recipient,
'Your requested account summary',
'Here is the account summary you requested.'
);
}
What else can it do?
Settings also provides manual AI rewrite and template-generation actions with separate paid confirmation. Price display needs vip:read; rewrite needs rewrite; generation needs ai:generate, and VIP generation requires active VIP membership. Results are escaped, copy-only text: never automatically applied or sent. Existing tokens do not gain scopes automatically.
Results, failures and limits
Advisory allows delivery; blocking compares the finite spam probability to your threshold. API timeouts and failures follow the separate failure policy, not a spam label. Opaque local locks suppress repeated analysis for 24 hours; unknown network outcomes are not retried automatically. Sends themselves are not deduplicated. Installed update checks covered a tracked 0.1.0 ZIP upgraded to 0.2.0, administrator nonce rejection/save and the selected WooCommerce path. A separate 40-scenario matrix covered both plugin load orders with WP Mail SMTP and FluentSMTP, including To/Cc/Bcc, Reply-To, headers, attachments, SMTP rejection and policy outcomes. These exact tuples do not certify other CMS, SMTP plugin or provider versions. Hooks that bypass wp_mail and later transport changes remain outside coverage. Deactivation preserves settings; uninstall removes credentials even when retaining disabled settings. Remove a wp-config token yourself.
WooCommerce email adapter
0.2.0
Included in the same SendRepute 0.2.0 ZIP as the WordPress plugin; there is no separate WooCommerce add-on or download. It requires the plugin's WordPress 5.7+, PHP 7.4+ and OpenSSL baseline. The adapter was source-reviewed against WooCommerce 10.4.3, not certified across every WooCommerce or mail-extension version.
WooCommerce analysis has its own administrator switch and exact built-in email-type selections, all off by default. The global analysis and paid-consent controls must also be on. Unselected and extension-defined types bypass analysis. Every selected built-in customer_* type is protected and advisory-only: it may be analyzed but is never blocked. Selected multipart mail fails classification before any paid request; advisory or fail-open preserves delivery, while fail-closed blocks only non-protected mail.
Download shared WordPress and WooCommerce ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
This is the same installable ZIP used by the WordPress guide. Install it once; do not install a second WooCommerce add-on. Activate SendRepute, then open Settings > SendRepute. Keep WordPress, WooCommerce, PHP and the real mail transport supported and updated.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-wp.zip
wp plugin install ./sendrepute-wp.zip --activate
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-wordpress.git
cd sendrepute-wordpress
python3 package.py
2. Configure securely
Use a scoped customer token from server secrets or the encrypted WordPress setting. First configure the shared non-paid connection check, current-price review, global paid consent, risk mode, threshold and failure policy. Then separately enable WooCommerce analysis and select only the built-in email types you have reviewed. Extension-defined types are never selected automatically.
// wp-config.php — keep the shared WordPress/WooCommerce token server-side.
$sendreputeToken = getenv('SENDREPUTE_API_TOKEN');
if (is_string($sendreputeToken) && $sendreputeToken !== '') {
define('SENDREPUTE_API_TOKEN', $sendreputeToken);
}
3. Use it deliberately
Continue sending through WooCommerce normally. The adapter wraps the callback already chosen by WooCommerce and preserves its original arguments and transport; it does not provide a new send method. If another filter mutates callback arguments, ordinary mail is nested during that callback, or a custom callback never calls wp_mail, analysis is conservatively bypassed rather than falling into the general paid path. Test selected non-critical types with a non-relaying mail sink.
Results, failures and limits
Selected single-part mail follows the shared WordPress advisory, threshold and failure policies, except every customer_* type is protected and advisory-only. Protected customer mail always continues after a high-risk result, API failure or unsupported content. WooCommerce constructs multipart alternatives after pre_wp_mail, so selected multipart mail fails before any paid request instead of being partially classified; only selected non-protected mail can be refused by fail-closed. Callback context is removed after success, failure and nested sends.
Drupal mail backend
0.1.0
Requires Drupal 10.3+ or 11.x and PHP 8.1+. Install the ZIP as a module, grant administer sendrepute only to trusted administrators, configure a bounded non-address sender display name, and select exact module/key mail routes. Version 0.1.0 supports Drupal core php_mail only; it is a Mail backend, not a provider or replacement transport. Installed-site evidence covers exact Drupal 10.6.17 and 11.4.7 releases with PHP 8.4.10.
Paid consent and every route are off by default. Each exact route uses the fixed core php_mail delegate, advisory or block mode, an independent preserve or block failure policy, threshold, and deliberate critical-mail selection. Account and security mail remains deliverable unless that exact route explicitly allows critical blocking. The same php_mail instance formats and sends one scalar final body; multipart and attachment-bearing output are unsupported.
Download Drupal ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Run from the Drupal project root, or upload the ZIP with Drupal's module installer. The archive contains a sendrepute module root suitable for modules/contrib. Enable it, grant administer sendrepute only to trusted administrators, and open Configuration > System > SendRepute.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-drupal.zip
unzip sendrepute-drupal.zip -d modules/contrib
drush en sendrepute -y
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-drupal.git
cd sendrepute-drupal
2. Configure securely
Store a classify-scoped SENDREPUTE_API_TOKEN only in the web/PHP process environment. It is never accepted by the form or exported in Drupal configuration. In the form, enter a required sender display name of at most 320 bytes with no address, angle brackets or controls. Add one seven-field line per exact route as shown; delegate must be php_mail. Choose advisory/block mode, preserve/block failure policy, threshold, and critical yes/no. Begin with advisory, preserve and no.
export SENDREPUTE_API_TOKEN="replace-with-a-scoped-server-token"
# Enter a non-address sender display name in Configuration > System > SendRepute.
# One exact route in Configuration > System > SendRepute:
# contact|page_mail|php_mail|advisory|preserve|0.90|no
3. Use it deliberately
Keep calling Drupal's normal mail manager. For an opted-in route, sendrepute_mail calls core php_mail's format(), analyzes that final scalar body, applies policy, and then calls the same cached php_mail instance's mail(). Other delegate IDs are rejected. It does not use hook_mail_alter and does not rewrite the message.
Results, failures and limits
A validated success blocks only at or above the configured threshold in block mode. The complete nested classification result and billing response are validated before spamProbability can affect delivery. API, authentication, balance, rate-limit, malformed, multipart, attachment-indicator and size failures follow the independent route failure policy, except protected critical mail continues. The installed 10.6.17/11.4.7 matrix covered installation and in-place ZIP replacement while enabled, real administrator login, Form API CSRF rejection/save, plugin discovery, route opt-in, synthetic classification, critical-mail preservation and core php_mail through a local sink. Baseline source checks also cover immutable 10.3.0 and 11.0.0 archives; neither result certifies every later patch or contributed mailer. The configured display name, non-empty subject and length-framed body are sent; addresses, recipients, headers, parameters and attachments are excluded. Subject is limited to 998 bytes and body to 256 KiB. There is one verified-HTTPS attempt, no redirects, retry or queue.
PrestaShop mail module
0.1.1
Version 0.1.1 supports exactly PrestaShop 9.0.0, 9.0.1, 9.0.2 and 9.0.3 with PHP 8.1–8.4. Upload the ZIP in Modules > Module Manager, then configure SendRepute mail classification. All four official prebuilt classic releases passed isolated installation, authenticated administrator configuration and ZIP-update checks; their unchanged Mail::send() implementations also passed the offline real-mail matrix. PrestaShop 8, 9.1+ and later unlisted 9.0 patches are not supported.
The module, paid/content consent, and exact template selection are all off by default. It analyzes the final rendered subject and every supported displayed body without rebuilding the Symfony message. A message containing both text/plain and text/html is sent in one bounded classification request: the plain alternative is made inert, the original HTML is preserved, and the service analyzes each typed alternative independently without concatenation. The result uses the highest risk with the complete content audits, produces one paid classification, and never returns a partial safety score. Advisory never interrupts sending. Threshold blocking and fail-closed throw one exception implementing both Symfony Mailer's ExceptionInterface and PrestaShop's ModuleErrorInterface; on every supported release the installed test observed Mail::send() return false with no SMTP delivery. Failure policy is independent of the risk threshold.
Download PrestaShop ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Download the 0.1.1 ZIP, then use Modules > Module Manager > Upload a module and choose it. Open Configure for SendRepute mail classification. Do not force installation outside exact PrestaShop 9.0.0–9.0.3: cancellation and signing behavior depend on the audited Mail::send() paths.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-prestashop.zip
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-prestashop.git
cd sendrepute-prestashop
2. Configure securely
Set SENDREPUTE_API_BASE to the canonical production SendRepute HTTPS origin supplied for this module and SENDREPUTE_API_TOKEN to a scoped server token in the PHP-FPM/server environment. The base must be a path-free public DNS HTTPS origin; literals, credentials, redirects and private DNS answers are refused. Run the non-paid account/pricing connection check, then explicitly enable the module, paid/content consent and exact template names. Choose advisory/block, threshold and open/closed failure policy independently.
export SENDREPUTE_API_BASE="replace-with-the-canonical-sendrepute-https-origin"
export SENDREPUTE_API_TOKEN="replace-with-a-scoped-server-token"
3. Use it deliberately
Continue using PrestaShop's normal Mail::send flow. The early hook only remembers an opted-in exact template. The final hook reads the already-rendered Symfony Email subject, text body and HTML body without changing recipients, headers, attachments or transport. For dual bodies, it submits inert plain text and the original HTML as typed alternatives in one request; independent service normalization prevents one fragment from consuming another while retaining visible HTML link and image destinations for audit. A single plain body stays on the narrow inert-text path, and a single HTML body stays on the narrow DOM-extraction path. Classification completes before PrestaShop creates a separate DKIM-signed message. The supported-release matrix verified the emitted multipart structure plus DKIM body hash and RSA signature after classification. PrestaShop's pinned signing path omits Bcc from the prepared signed headers and loses that blind SMTP recipient; valid signature evidence therefore does not establish Bcc delivery compatibility. Do not combine DKIM and Bcc on this supported path. Unsupported display sources, active semantics, ambiguous quoted-printable or base64 HTML, and oversized aggregate content follow the configured failure policy before payment. Leave critical templates unselected unless deliberately approved.
Results, failures and limits
The classifier accepts one text/plain body, one text/html body or both as independently analyzed displayed alternatives. Literal text, entity, hidden and style content in an accepted alternative cannot consume or hide a later alternative; ambiguous quoted-printable or base64 HTML is rejected before payment instead. Any accepted alternative can determine the highest-risk result, while content audits cover every alternative; classification is charged once only after the complete bounded input is accepted. The required legacy body exactly duplicates the inert plain alternative for a dual message, and that duplicate plus both typed alternatives share the exact 524288-byte request budget. Recipients, attachments and embedded resources are excluded, and the original pre-signing transport message is preserved. The real-mail fixture separately checks MIME/signature integrity and actual SMTP recipients: DKIM signatures remain valid after classification, but the audited upstream signed path does not preserve Bcc recipients. A validated classification stores a limited latest advisory summary. Block mode throws only at or above the threshold; the dual-interface exception survives hook dispatch and produces false before transport on all four installed releases. Unsupported content, API and validation errors follow open/closed independently. One HTTPS attempt uses pinned public DNS, verified TLS, finite timeouts, a 256 KiB response cap, no redirects and no retry. Blocking relies on the audited PrestaShop Mail::send() exception catch, not the final hook return value.
Symfony Mailer adapter
0.1.1
Requires PHP 8.1+ and targets Symfony Mailer 6.4 or 7.4 only; the exact verified releases are 6.4.46 and 7.4.19. No Symfony 8.1 or untested-line compatibility is claimed. Install the local source ZIP through a Composer path repository; this package is not published to Packagist.
The bundle and paid consent are off by default, and only a message with the exact configured opt-in header is eligible. Advisory or blocking score policy is independent from allow or block failure policy. Classification runs on the official pre-send MessageEvent; rejection uses MessageEvent::reject(). Queued clone events are skipped so the worker transport event is the one paid classification point.
Download Symfony source ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Extract the downloaded ZIP into a retained packages directory, register that directory as a Composer path repository, require the exact 0.1.1 package, and register SendRepute\Symfony\SendReputeBundle if Flex does not. The source archive is local and unpublished.
mkdir -p packages
curl -fL https://www.sendrepute.com/downloads/sendrepute-symfony.zip -o packages/sendrepute-symfony.zip
unzip packages/sendrepute-symfony.zip -d packages
composer config repositories.sendrepute path ./packages/sendrepute-symfony
composer require sendrepute/symfony:0.1.1
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-symfony.git
cd sendrepute-symfony
2. Configure securely
Resolve SENDREPUTE_API_TOKEN from server secrets. Keep enabled and paid_analysis_consent false while reviewing current pricing. Mode, threshold and failure policy are independent. The endpoint is fixed to verified HTTPS with bounded deadlines, no redirects or retries, and a 1 MiB response cap.
send_repute:
enabled: false
paid_analysis_consent: false
api_token: '%env(SENDREPUTE_API_TOKEN)%'
mode: advisory
failure_policy: allow
spam_probability_threshold: 0.8
3. Use it deliberately
Add the exact opt-in header only to reviewed non-critical Email objects, then continue through the normal Mailer. The message, envelope, transport and header are not rewritten. For Messenger delivery, configure the bundle in workers: producer clone events are intentionally not classified.
$email->getHeaders()->addTextHeader('X-SendRepute-Classify', 'yes');
$mailer->send($email);
Results, failures and limits
Exactly one in-memory text or HTML body is supported. Mixed alternatives, textual DataParts, streams or paths, CSS braces, markup, quoted-printable syntax, base64 headers or whole-body base64 fail before payment and follow failure policy; ordinary braces-free content is unchanged. Every required nested response field and optional audit branch is validated and unknown properties are rejected. Advisory never score-blocks; blocking rejects at the threshold through the real transport event.
Rails Action Mailer adapter
0.1.0
Requires Ruby 3.2+ and is narrowly verified with real Action Mailer 7.1.6 and Mail 2.9.1; the callback path was also observed on Action Mailer 7.2.3.2. This is not certification of every allowed Rails 7.x release. Install the local source ZIP through Bundler; no RubyGems publication is claimed.
Both global paid gates default off, and each mailer action must call sendrepute_paid_preflight! explicitly. Advisory/block score behavior and preserve/block failure behavior are independent. Password resets, MFA, login, verification, billing and security routes should remain unselected. Every multipart message and ambiguous CSS, quoted-printable or base64-looking content is rejected before payment; one accepted decoded text or HTML body is analyzed without changing the original message or transport.
Download Rails source ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Extract the ZIP exactly into vendor/sendrepute-rails, add the local path entry to the Gemfile, run Bundler in your controlled environment, and include SendRepute::Rails::Mailer in ApplicationMailer. This is not a RubyGems installation.
# Download sendrepute-rails.zip, then extract it into vendor/sendrepute-rails.
gem "sendrepute-rails", path: "vendor/sendrepute-rails"
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-rails.git
cd sendrepute-rails
2. Configure securely
Keep enabled and paid_consent false until current pricing and routes are reviewed. Read the token from Rails credentials or another server secret. Configure advisory/block, preserve/block and threshold independently; on_result and on_error callbacks must not log message content, authorization data or complete responses.
SendRepute::Rails.configure do |config|
config.enabled = false
config.paid_consent = false
config.token = Rails.application.credentials.dig(:sendrepute, :api_token)
config.mode = :advisory
config.failure_policy = :preserve
config.score_threshold = 0.8
end
3. Use it deliberately
Call sendrepute_paid_preflight! only inside each deliberately selected non-critical mailer action. Normal actions bypass classification. The paid hook uses Action Mailer's before_deliver route; no global auto-opt-in is provided and the adapter does not rewrite the Mail::Message.
class ApplicationMailer < ActionMailer::Base
include SendRepute::Rails::Mailer
end
def newsletter
sendrepute_paid_preflight!
mail(to: params[:to], subject: "News")
end
Results, failures and limits
One decoded text/plain or text/html displayed body is supported. Every multipart or ambiguous normalizer input fails before payment and follows failure policy. A complete typed nested response can block only in block mode at or above threshold; advisory preserves every score. Result and error callbacks receive immutable safe data, and callback exceptions or throw(:abort) are caught locally so they cannot terminate advisory or preserve delivery. The fixed endpoint refuses redirects and retries and uses a bounded total deadline. Real Action Mailer 7.1.6 tests passed: 19 runs and 59 assertions; no paid request or real delivery occurred.
Spring JavaMailSender adapter
0.1.1
Requires Java 17+ and targets Spring Framework 6.2.x JavaMailSender; exact dependency verification used Spring Framework 6.2.19. There is no Spring Boot 4 or broad framework-version claim. Build the local source ZIP with Maven; it is not published to Maven Central or another registry.
The decorator, paid consent, advisory mode and allow-on-failure defaults are explicit. Only sendWithSendRepute(...) performs paid pre-send analysis; every ordinary send(...) overload bypasses classification and delegates unchanged. Use ordinary send for critical mail unless that individual send is deliberately selected. Supported displayed MIME alternatives are inertly framed together; unsupported, nested, signed, encrypted or ambiguous content fails before payment.
Download Spring Java source ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Extract the 0.1.1 source ZIP, run mvn verify, and install it only into your controlled local Maven repository. The consuming application supplies its existing JavaMailSender and runtime mail implementation. Exact dependency verification used Java 17 bytecode, Spring Framework 6.2.19 and the versions documented in the included README.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-spring-mail.zip
unzip sendrepute-spring-mail.zip
cd sendrepute-spring-mail-0.1.1
mvn verify
mvn install
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-java.git
cd sendrepute-java
2. Configure securely
Construct SendReputeConfiguration from a server-side token and explicit switches. Keep enabled and paidAnalysisConsent false until pricing and selected calls are reviewed. Advisory/blocking, threshold, and allow/block failure policy are independent. The endpoint is fixed to verified HTTPS with no redirect or retry.
var settings = new SendReputeConfiguration(
token, false, false,
SendReputeConfiguration.Mode.ADVISORY,
SendReputeConfiguration.FailurePolicy.ALLOW,
0.80, Duration.ofSeconds(3), Duration.ofSeconds(10));
var reviewedSender = new SendReputeJavaMailSender(existingSender, settings);
3. Use it deliberately
Call sendWithSendRepute(...) only for an individual SimpleMailMessage, MimeMessage or MimeMessagePreparator that should incur analysis. Single and varargs overloads are supported. Every normal send(...) overload bypasses classification. Preparators render once and the original prepared MIME is delegated after policy permits.
// Paid classification is possible only on this explicit method.
reviewedSender.sendWithSendRepute(reviewedMessage);
// Every ordinary JavaMailSender send overload bypasses classification.
reviewedSender.send(criticalMessage);
Results, failures and limits
All supported displayed plain and HTML parts are analyzed; recipients and attachments are excluded. Traversal is capped at 16 levels, 256 parts and 524,288 displayed UTF-8 bytes. Ignored inline binary is never materialized; unknown or unbounded lazy displayed sources fail before a stream is opened or a paid request is made, and supported source reads are bounded. Numeric-entity framing keeps fragments inert through the checked server normalizer order. Entire varargs batches prepare and normalize before the first paid request, and inspection does not generate Jakarta Mail headers. A recursively exact nested response is required.
Magento Open Source mail adapter
0.1.1
Supports only Magento Open Source 2.4.7-p5 and 2.4.7-p6 with the exact immutable mail-interface sources reviewed. Offline typed fixtures passed, but no full Magento installation was performed; no other Magento or Adobe Commerce release is certified. Install the local ZIP through a Composer path repository; it is not an Adobe Marketplace package.
The module, paid consent and route lists all default off. Every template identifier requires two independent exact approvals; criticality is never inferred from its name. The aroundSendMessage plugin analyzes at the final transport boundary without rebuilding the message. Advisory/block threshold policy and preserve/block failure policy are independent; blocking raises a visible Magento MailException. Multiple displayed MIME parts and ambiguous content fail before payment.
Download Magento source ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Extract the ZIP to a retained package directory, register its SendRepute_MailAdapter root as a Composer path repository, require version 0.1.1, then use Magento's normal module enable and setup upgrade process. Do not represent this local archive as an Adobe Marketplace package.
mkdir -p packages/sendrepute-magento
curl -fLO https://www.sendrepute.com/downloads/sendrepute-magento.zip
unzip sendrepute-magento.zip -d packages/sendrepute-magento
composer config repositories.sendrepute path ./packages/sendrepute-magento/SendRepute_MailAdapter
composer require sendrepute/magento-mail-adapter:0.1.1
bin/magento module:enable SendRepute_MailAdapter
bin/magento setup:upgrade
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-magento.git
cd sendrepute-magento
2. Configure securely
Set SENDREPUTE_API_TOKEN only in the PHP-FPM and CLI server environment. In Stores > Configuration > Services > SendRepute, keep the module and paid consent off initially. Add every exact template identifier to both independent route-approval lists; names, including numeric names, never infer criticality. Configure advisory/block, threshold and preserve/block failure behavior separately.
export SENDREPUTE_API_TOKEN="replace-with-a-scoped-server-token"
# Then configure Stores > Configuration > Services > SendRepute.
3. Use it deliberately
Continue using Magento's normal template and transport flow. Route correlation records the exact identifier and store selected through TransportBuilder, while the final aroundSendMessage plugin reads the official typed email and MIME interfaces before calling the same transport. Builder state clears in finally, and builder/message correlations use object-keyed WeakMap entries so an abandoned built transport cannot leave reusable numeric object-ID authorization. The adapter does not provide a new send method or mutate the message.
Results, failures and limits
Only one supported displayed MIME part is accepted; attachments are preserved but excluded from analysis. Multiple displayed parts, unsupported transfer encodings or charsets, streams, nested MIME and ambiguous normalizer text fail before payment. One verified-HTTPS request has bounded deadlines and response size with no retry or redirect. A valid nested result may block at threshold; configured fail-block raises Magento MailException.
.NET MailKit adapter
0.1.0
Requires .NET 8 and exact dependency evidence for MailKit/MimeKit 4.18.0. It is an explicit wrapper around an application-owned IMailTransport, not a global hook, SMTP client or replacement transport. Build or reference the local source ZIP; no NuGet publication is claimed.
The adapter and paid consent default off; advisory and preserve-send are independent defaults. Calls to AnalyzeAsync, AnalyzeThenSend or AnalyzeThenSendAsync are explicit. Critical security/account mail needs a separate per-call category and consent. Every supported displayed plain/HTML alternative is inertly framed into one bounded request; unsupported, nested, signed or encrypted content fails before payment. The original MimeMessage and cancellation token reach the existing transport only after policy permits.
Download .NET MailKit source ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Extract the source ZIP and reference src/SendRepute.MailKit/SendRepute.MailKit.csproj from the consuming .NET 8 project. Restore obtains MailKit/MimeKit 4.18.0. This source package is local and unpublished; it is not a NuGet installation.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-mailkit.zip
unzip sendrepute-mailkit.zip
dotnet add reference ./sendrepute-mailkit-0.1.0/src/SendRepute.MailKit/SendRepute.MailKit.csproj
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-dotnet.git
cd sendrepute-dotnet
2. Configure securely
Wrap the existing application-owned IMailTransport with SendReputeMailAdapter. Read the API token from server configuration and keep Enabled and PaidAnalysisConsent false until reviewed. Advisory/block threshold and preserve/block failure settings are independent. The endpoint, TLS floor, one-attempt behavior, deadlines and 1 MiB bounds are fixed.
var options = new SendReputeOptions {
Enabled = false,
PaidAnalysisConsent = false,
ApiToken = configuration["SENDREPUTE_API_KEY"]!,
Enforcement = EnforcementPolicy.Advisory,
OnFailure = FailurePolicy.PreserveSend,
SpamProbabilityThreshold = 0.80
};
var adapter = new SendReputeMailAdapter(existingTransport, new SendReputeClient(options), options);
3. Use it deliberately
Invoke AnalyzeAsync for analysis only, or AnalyzeThenSend and AnalyzeThenSendAsync for explicit pre-send behavior. No ordinary or global mail path is intercepted. Pass paid consent and the message category on each selected operation; critical security/account mail requires the separate critical-consent setting.
await adapter.AnalyzeThenSendAsync(message, new AnalysisConsent {
PaidAnalysisConsent = true,
Category = MessageCategory.Ordinary
}, cancellationToken);
Results, failures and limits
Actual MimeKit decoding collects every supported displayed plain and HTML alternative into inert framing while excluding recipients and attachments. Non-base64 outer framing and late-decoded entities neutralize CSS braces, quoted-printable text, base64 headers, whole-body base64 and markup before service normalization. Unsupported, nested, signed or encrypted displayed content fails before payment. Every required response field is typed; optional flaggedTermCount must be a non-negative integer and optional contentAudit is fully and recursively validated against the public contract. The exact original MimeMessage and cancellation token reach the supplied transport only when independent score and failure policies permit.
Zapier manual draft analysis
0.2.0
Manual Zapier recipe for displaying paid analysis of exactly three owner-selected draft strings. It is not a SendRepute Zapier app, marketplace listing, import artifact, pre-send adapter, sender, allow/block route or whole-message classifier. Zapier Webhooks uses an owner-operated bounded HTTPS proxy because the SendRepute token must not enter the Zap.
Two compile-time constants default false before HTTP. The Zap maps sender display name, subject and body only, posts JSON to the included owner-proxy design, completely validates the nested response, then displays advisory and billing fields in a private review step. It must not add a sender, Paths enforcement, Autoreplay or failure-preserve route; failed Code or Webhook steps stop.
Download Zapier and Make recipe ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Download and extract the shared 0.2.0 recipe source. Read the included Zapier guide and deploy the included loopback Node proxy only behind an owner-managed HTTPS reverse proxy. This package does not deploy it. There is no SendRepute Zapier app or importable Zap artifact.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-automation-recipes.zip
unzip sendrepute-automation-recipes.zip
cd sendrepute-automation-recipes
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-automation.git
cd sendrepute-automation
2. Configure securely
Keep the Zap off. In the exact preflight Code source, ENABLED and PAID_CONSENT both remain false until paid use is reviewed. The owner proxy stores SENDREPUTE_API_TOKEN; the Zap receives only one separately revocable credential from SENDREPUTE_PROXY_CREDENTIALS. Editors and task history may expose it, so restrict, rotate and revoke it. Configure per-credential token-bucket and concurrency limits, global connection/concurrency caps, a persistent owner-set daily paid-call budget, restrictive upstream spend limits, and matching TLS-terminator size/rate/deadline controls. Do not enable Autoreplay.
// In zapier/preflight.js; review charges before changing either literal.
const ENABLED = false;
const PAID_CONSENT = false;
3. Use it deliberately
Build the steps manually: draft trigger; preflight Code mapping only sender, subject and body; Webhooks POST with JSON rows to the owner proxy; response-validation Code; private review display. Never manually interpolate raw JSON. Display requestId, model, label, spamProbability and billing only; do not add a mail action or Paths decision.
{
"sender": "Mapped draft sender display name",
"subject": "Mapped draft subject",
"body": "Mapped draft body"
}
Results, failures and limits
The recipe analyzes only the three mapped strings; unmapped MIME, HTML alternatives, attachments and eventual outbound content remain unanalyzed. Conservative preflight rejects known normalizer triggers but does not prove whole-message coverage. Proxy rate, concurrency and daily-budget limits reject before upstream, and budget reservation persists before the paid attempt; run one proxy process per budget file. The proxy makes one bounded fixed-HTTPS attempt. Any non-200 or incomplete exact response throws and stops; there is no preserve, Resume or substitute result.
Make manual draft analysis
0.2.0
Manual Make scenario instructions for displaying paid analysis of exactly three selected draft strings. It is not a blueprint, approved SendRepute app, mail sender, enforcement route or claim about unmapped MIME, HTML, attachments or eventual outbound content. The bearer token belongs only in Make HTTP's secure keychain.
Persisted enabled and paidConsent booleans default false and an AND filter stops before HTTP. JSON is produced by Make's JSON module and sent once by the HTTP module with redirects and retries disabled. A response filter is only a display guard, not full validation or permission to send. HTTP failures use Break, never Resume or substitute output.
Download Zapier and Make recipe ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Download and extract the shared 0.2.0 recipe source, then follow the included Make guide to construct current native modules manually. No blueprint, marketplace app or import format is claimed. Keep scenario scheduling off while testing against a mock endpoint.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-automation-recipes.zip
unzip sendrepute-automation-recipes.zip
cat sendrepute-automation-recipes/make/README.md
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-automation.git
cd sendrepute-automation
2. Configure securely
Create persisted boolean Tools variables enabled=false and paidConsent=false, followed by an AND filter requiring both true. Use JSON > Create JSON for exactly sender, subject and body. Store the SendRepute bearer token only in the HTTP app secure keychain; exported scenarios must contain no credential.
Tools variables: enabled = false; paidConsent = false
Filter: enabled = true AND paidConsent = true
HTTP credential: secure keychain; Authorization header
Body type: Raw; Content type: application/json; map serialized JSON
Follow redirect: No; Timeout: 10 seconds; no retry
Response filter: Minimal display guard
3. Use it deliberately
Configure one HTTP POST to the fixed classify URL. Select Body type Raw and the application/json content-type control without adding a conflicting free-text header, then map the serialized output from JSON > Create JSON. Enable parsed response, disable redirects, set a 10-second timeout, and add no repeater or automatic retry. Require the module's 1 MiB response limit; if unavailable, use an owner-controlled bounded proxy instead. Add only a private review display after the Minimal display guard—never a sender or allow/block router.
{
"sender": "Mapped draft sender display name",
"subject": "Mapped draft subject",
"body": "Mapped draft body"
}
Results, failures and limits
Only the mapped strings are analyzed; normalization is not identity with an original or outbound email. The response filter checks status and core result/billing presence only and is explicitly not full schema validation or enforcement. HTTP errors use Break so later actions do not run; never use Resume, fabricated output or a failure-preserve route.
Node.js SDK
0.1.1
Server-only SDK for Node.js 18.17+. Install @sendrepute/node from npm or use the downloadable tarball. The optional Nodemailer adapter preserves your existing transport. Set a scoped API key and an explicit API base URL in your server environment, never browser code.
Register createSendReputePlugin at the stream stage only after reviewing pricing and deliberately enabling paid analysis consent. Advisory mode reports findings without blocking delivery. Blocking mode enforces spamProbabilityThreshold; onApiFailure chooses allow or block, while a changed-price refusal always blocks delivery. Classification is a paid API operation.
Download Node.js tarball
Public source repository
Full README and examples
Security notes and known limitations
View verified npm package
1. Install
The verified npm package is @sendrepute/node version 0.1.1; pin registry installs to @sendrepute/node@0.1.1. The website tarball and pinned public repository provide the 0.1.1 release source and build. Nodemailer is optional and only needed for the transport adapter. The SDK supports typed customer API requests for account, catalog, classification, AI and builders. Use it in a Node.js server, never a browser bundle.
npm install @sendrepute/node nodemailer
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
npm install @sendrepute/node@0.1.1
npm install nodemailer
2. Configure securely
Inject SENDREPUTE_API_KEY from your server secret store and set the explicit base URL below for the hosted customer API. Do not paste secrets into commands, source files or logs. Grant only the scopes your operations require. The setup uses a local rendering transport, not SMTP; maxRetries is set to zero here to make paid attempts deliberate.
export SENDREPUTE_API_BASE_URL=https://www.sendrepute.com/api
Nodemailer setup
This example configures a local rendering transport and does not call sendMail. Sending through the configured plugin performs a paid analysis. Replace the local transport with your existing SMTP transport only when ready.
import nodemailer from "nodemailer";
import { SendReputeClient } from "@sendrepute/node";
import { createSendReputePlugin } from "@sendrepute/node/nodemailer";
const apiKey = process.env.SENDREPUTE_API_KEY;
const baseUrl = process.env.SENDREPUTE_API_BASE_URL;
if (!apiKey || !baseUrl) {
throw new Error("SENDREPUTE_API_KEY and SENDREPUTE_API_BASE_URL are required");
}
const client = new SendReputeClient({ apiKey, baseUrl, maxRetries: 0 });
const transporter = nodemailer.createTransport({
streamTransport: true,
buffer: true,
newline: "unix",
});
transporter.use("stream", createSendReputePlugin({
client,
policy: {
paidAnalysisConsent: true,
mode: "blocking",
spamProbabilityThreshold: 0.85,
onApiFailure: "block",
},
}));
3. Use it deliberately
Use the client from the setup above. Read account and current pricing before displaying a consent action. Invoke classifyAfterConsent only from an authenticated server action after confirmation; it returns the typed classification and billing response. Sending through the configured Nodemailer plugin is also a paid classification action. The adapter requires paidAnalysisConsent: true and rejects any other value before registration; set it only after authorization.
// Uses client from the setup above; nothing calls this function automatically.
async function classifyAfterConsent({ sender, subject, body, confirmed }) {
if (confirmed !== true) throw new Error("Paid consent required");
return client.request("classifyCustomerEmail", { body: { sender, subject, body } });
}
async function readAccountAndPricing() {
return Promise.all([
client.request("customerGetAccount", {}),
client.request("customerGetPricingSettings", {}),
]);
}
Standard and native VIP builders
The free standard builder imports, validates, compiles and exports MJML as HTML, MJML or a ZIP of both. The separate native VIP builder uses its own document format, not MJML: its import, validate, compile and export operations require active membership and an owned, open access entitlement, and its ZIP contains three HTML CSS variants. Optional AI generation is separately paid, producing an editable standard MJML or native VIP design; show current effective pricing and pass confirmed expectedPriceMillicents, never a hard-coded price. ZIP responses contain archiveBase64, not an html field: decodeExportBytes returns bytes for your application to save. These processing endpoints do not fetch assets, persist designs or send email.
import { decodeExportBytes } from "@sendrepute/node";
async function exportStandardZip(mjml) {
const exported = await client.request("customerStandardBuilderExport", {
body: { mjml, format: "zip", filename: "newsletter.zip" },
});
return decodeExportBytes(exported);
}
async function generateNativeAfterConsent(prompt, expectedPriceMillicents, confirmed) {
if (confirmed !== true) throw new Error("Paid consent required");
return client.request("customerCreateVipEmailTemplate", {
body: { prompt, expectedPriceMillicents },
});
}
What else can it do?
Generated operation IDs cover account and pricing reads, classification and manual edits, AI rewrite/template generation, VIP plans/status/purchases, native templates/access entitlements, and stateless standard/native import/export. Consult the source examples and customer API reference for each request type, required scope and current price. Catalog reads do not purchase access. New paid capabilities require deliberately scoped tokens and explicit UI confirmation.
Results, failures and limits
SendReputeError exposes status, code and requestId; retain only that safe operational metadata. Never log bodies, prompts, headers or complete responses. AbortSignal cancels work; timeoutMs applies per attempt. Bounded retries are operation-aware and receipt protection is time-limited, not unlimited exactly-once billing. Advisory Nodemailer mode reports without blocking; blocking uses spamProbabilityThreshold and onApiFailure independently. Preserve and test your real transport separately.
import { SendReputeError } from "@sendrepute/node";
async function readAccountSafely() {
try {
return await client.request("customerGetAccount", {});
} catch (error) {
if (error instanceof SendReputeError) {
console.error({
status: error.status, code: error.code, requestId: error.requestId,
});
}
throw error;
}
}
API and method reference
SendReputeClient requires apiKey and baseUrl; optional timeoutMs defaults to 30000 (maximum 300000), maxRetries defaults to 2 (range 0–10), and fetch accepts a compatible server implementation. request(operationId, input, { signal }) returns the operation's typed response; input contains its body, path and/or query fields. Invalid configuration raises TypeError; API failures use SendReputeError with status, code, requestId and retryAfterMs. decodeExportBytes converts a ZIP export to Uint8Array and rejects non-ZIP or invalid base64 input. OperationInput, OperationResponse and generated schema types are exported for TypeScript callers.
Alternative: wrap a low-level Nodemailer transport
createSendReputeTransport(existingTransport, options) wraps an existing transport object with send, optional close and verify methods; it is not a sendMail transporter. Choose this or createSendReputePlugin, not both, to avoid double analysis. Both take client and policy plus optional model, sender string/resolver, signal and onDiagnostic. Diagnostic callbacks cannot change delivery. SendReputeNodemailerError codes distinguish invalid policy/message, unsupported content, spam blocks and API-failure blocks. The published npm 0.1.1 package and website 0.1.1 download combine all displayed in-memory text/plain and text/html alternatives into one bounded classification request; in blocking mode they reject unsupported displayed alternatives. Raw messages, streams, paths and URLs remain unsupported.
import { createSendReputeTransport } from "@sendrepute/node/nodemailer";
function wrapExistingTransport(existingTransport) {
return createSendReputeTransport(existingTransport, {
client,
policy: {
paidAnalysisConsent: true,
mode: "advisory",
spamProbabilityThreshold: 0.85,
onApiFailure: "block",
},
onDiagnostic(diagnostic) {
console.info(diagnostic.kind, diagnostic.action);
},
});
}
All 49 customer API operations
Expand an operation to see its exact SDK input type, return type, scope and documented HTTP statuses. The schema link opens its complete parameters, response fields and examples in the customer API reference. These wrappers use the configured client above; confirmation is required and nothing executes automatically. Read operations do not authorize purchases. Mutations, payments, access closure and paid AI require the corresponding deliberate account action.
Quote one aggregate campaign insights analysis
POST /v1/campaign-insights/quote
Required scope: ai:generate
Input: { body: CustomerCampaignInsightsQuoteInput; }
Returns: CustomerCampaignInsightsQuote
Documented HTTP statuses: 200, 400, 401, 403, 429, 503
Parameters, schemas and HTTP examples
// The configured server-side client needs ai:generate scope.
// A quote is free; it does not authorize or start paid analysis.
const quote = await client.request("customerQuoteCampaignInsights", { body: {} });
// quote.priceMillicents: 10000 (USD 0.10) regular, 5000 (USD 0.05) active VIP.
// The quoted rate can change; obtain fresh consent before analysis.
Analyze aggregate campaign delivery metrics with AI
POST /v1/campaign-insights/analyze
Required scope: ai:generate
Input: { body: CustomerCampaignInsightsAnalyzeInput; }
Returns: CustomerCampaignInsightsAnalysis
Documented HTTP statuses: 200, 400, 401, 402, 403, 409, 413, 429, 502, 503
Parameters, schemas and HTTP examples
import { randomUUID } from "node:crypto";
import type { CustomerCampaignInsightsMetrics } from "@sendrepute/node";
async function analyzeReviewedAggregate(
metrics: CustomerCampaignInsightsMetrics,
paidConsent: boolean,
) {
if (paidConsent !== true) throw new Error("Explicit price consent required");
// Aggregate counts/rates only: never include campaign IDs, contacts,
// message bodies or individual events. Requires ai:generate scope.
const quote = await client.request("customerQuoteCampaignInsights", { body: {} });
const body = {
analysisId: randomUUID(), // Persist this opaque ID and exact body for safe replay.
expectedPriceMillicents: quote.priceMillicents,
consent: true as const,
metrics,
};
// USD 0.10 regular or USD 0.05 active VIP; no automatic retry on a paid request.
// 409 PRICE_CHANGED requires a new quote and fresh consent, not blind retry.
// Aggregate input and result expire after 30 days.
return client.request("customerAnalyzeCampaignInsights", { body });
}
List customer API classifier models
GET /v1/models
Required scope: models:read
Input: Record<string, never>
Returns: CustomerApiModelsResponse
Documented HTTP statuses: 200, 401, 403, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function getCustomerApiModels(
input: OperationInput<"getCustomerApiModels">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"getCustomerApiModels">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("getCustomerApiModels", input, { signal });
}
Get customer API usage and limits
GET /v1/usage
Required scope: usage:read
Input: Record<string, never>
Returns: CustomerApiUsageResponse
Documented HTTP statuses: 200, 401, 403, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function getCustomerApiUsage(
input: OperationInput<"getCustomerApiUsage">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"getCustomerApiUsage">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("getCustomerApiUsage", input, { signal });
}
Classify one customer email
POST /v1/classify
Required scope: classify
Input: { body: CustomerClassificationInput; }
Returns: CustomerClassificationResponse
Documented HTTP statuses: 200, 400, 401, 402, 403, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function classifyCustomerEmail(
input: OperationInput<"classifyCustomerEmail">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"classifyCustomerEmail">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("classifyCustomerEmail", input, { signal });
}
Get the current account and balance
GET /v1/account
Required scope: account:read
Input: Record<string, never>
Returns: Account
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetAccount(
input: OperationInput<"customerGetAccount">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetAccount">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetAccount", input, { signal });
}
Get the current account's referral link and reward activity
GET /v1/account/referrals
Required scope: account:read
Input: { query?: { page?: number; pageSize?: number; }; }
Returns: ReferralDashboard
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetAccountReferrals(
input: OperationInput<"customerGetAccountReferrals">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetAccountReferrals">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetAccountReferrals", input, { signal });
}
List current account credit ledger
GET /v1/account/ledger
Required scope: billing:read
Input: { query?: { kind?: "usage" | "payments"; limit?: number; offset?: number; }; }
Returns: Array<CreditLedgerEntry>
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetCreditLedger(
input: OperationInput<"customerGetCreditLedger">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetCreditLedger">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetCreditLedger", input, { signal });
}
List current account Bitcoin invoices
GET /v1/payments/invoices
Required scope: billing:read
Input: { query?: { limit?: number; offset?: number; }; }
Returns: Array<BitcoinInvoice>
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerListPaymentInvoices(
input: OperationInput<"customerListPaymentInvoices">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerListPaymentInvoices">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerListPaymentInvoices", input, { signal });
}
Create a USD-denominated Bitcoin deposit invoice
POST /v1/payments/invoices
Required scope: billing:write
Input: { body: InvoiceInput; }
Returns: BitcoinInvoice
Documented HTTP statuses: 201, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerCreatePaymentInvoice(
input: OperationInput<"customerCreatePaymentInvoice">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerCreatePaymentInvoice">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerCreatePaymentInvoice", input, { signal });
}
Hide an unpaid Bitcoin invoice
DELETE /v1/payments/invoices/{invoiceId}
Required scope: billing:write
Input: { path: { invoiceId: string; }; }
Returns: undefined
Documented HTTP statuses: 204, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerDeletePaymentInvoice(
input: OperationInput<"customerDeletePaymentInvoice">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerDeletePaymentInvoice">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerDeletePaymentInvoice", input, { signal });
}
GET /payments/methods
GET /v1/payments/methods
Required scope: billing:read
Input: Record<string, never>
Returns: Array<PaymentMethod>
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerListPaymentMethods(
input: OperationInput<"customerListPaymentMethods">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerListPaymentMethods">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerListPaymentMethods", input, { signal });
}
Get the currently active Bitcoin deposit bonus offer
GET /v1/payments/deposit-offer
Required scope: billing:read
Input: Record<string, never>
Returns: DepositBonusOffer | null
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetActiveDepositOffer(
input: OperationInput<"customerGetActiveDepositOffer">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetActiveDepositOffer">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetActiveDepositOffer", input, { signal });
}
Refresh confirmations for current account invoices
POST /v1/payments/refresh
Required scope: billing:write
Input: Record<string, never>
Returns: Array<BitcoinInvoice>
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerRefreshMyPayments(
input: OperationInput<"customerRefreshMyPayments">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerRefreshMyPayments">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerRefreshMyPayments", input, { signal });
}
Get current public analysis and editing prices
GET /v1/pricing
Required scope: catalog:read
Input: Record<string, never>
Returns: PricingSettings
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetPricingSettings(
input: OperationInput<"customerGetPricingSettings">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetPricingSettings">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetPricingSettings", input, { signal });
}
Get the current public VIP quote and comparison prices
GET /v1/vip/plans
Required scope: catalog:read
Input: Record<string, never>
Returns: VipPlanQuote
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetVipPlans(
input: OperationInput<"customerGetVipPlans">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetVipPlans">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetVipPlans", input, { signal });
}
GET /vip
GET /v1/vip
Required scope: vip:read
Input: Record<string, never>
Returns: VipState
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetVip(
input: OperationInput<"customerGetVip">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetVip">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetVip", input, { signal });
}
POST /vip/purchase
POST /v1/vip/purchase
Required scope: vip:purchase
Input: { body: CustomerVipPurchaseInput; }
Returns: VipPurchaseResult
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerPurchaseVip(
input: OperationInput<"customerPurchaseVip">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerPurchaseVip">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerPurchaseVip", input, { signal });
}
Quote an edit and recheck against a saved classification
POST /v1/rewrite/quote
Required scope: rewrite
Input: { body: EditQuoteInput; }
Returns: EditQuote
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerQuoteClassificationEdit(
input: OperationInput<"customerQuoteClassificationEdit">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerQuoteClassificationEdit">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerQuoteClassificationEdit", input, { signal });
}
Quote an edit and recheck against a saved classification
POST /v1/classify/edit/quote
Required scope: classify
Input: { body: EditQuoteInput; }
Returns: EditQuote
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerQuoteManualClassificationEdit(
input: OperationInput<"customerQuoteManualClassificationEdit">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerQuoteManualClassificationEdit">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerQuoteManualClassificationEdit", input, { signal });
}
Classify an email using sender name, subject, and body
POST /v1/classify/edit
Required scope: classify
Input: { body: CustomerManualEditInput; }
Returns: CustomerManualEditResult
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerClassifyEmail(
input: OperationInput<"customerClassifyEmail">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerClassifyEmail">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerClassifyEmail", input, { signal });
}
Request a separately paid AI rewrite of selected flagged terms and reclassify the result
POST /v1/rewrite
Required scope: rewrite
Input: { body: CustomerAiRewriteInput; }
Returns: AiRewriteResult
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 502, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerRewriteFlaggedTermsWithAi(
input: OperationInput<"customerRewriteFlaggedTermsWithAi">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerRewriteFlaggedTermsWithAi">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerRewriteFlaggedTermsWithAi", input, { signal });
}
Verify one exact rendered final draft against an owned paid Rewrite All receipt without another debit
POST /v1/rewrite/finalize
Required scope: rewrite
Input: { body: { requestId: string; sender: string; subject: string; body: string; }; }
Returns: { requestId: string; input: RewrittenClassificationInput; classification: ClassificationResult; }
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerFinalizeAiRewrite(
input: OperationInput<"customerFinalizeAiRewrite">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerFinalizeAiRewrite">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerFinalizeAiRewrite", input, { signal });
}
Recover an owned completed paid AI rewrite receipt
GET /v1/rewrite/result/{requestId}
Required scope: rewrite
Input: { path: { requestId: string; }; }
Returns: AiRewriteResult
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetAiRewriteResult(
input: OperationInput<"customerGetAiRewriteResult">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetAiRewriteResult">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetAiRewriteResult", input, { signal });
}
Quote the maximum authorized price of a separately paid AI rewrite
POST /v1/rewrite/ai-quote
Required scope: rewrite
Input: { body: AiRewriteQuoteInput; }
Returns: AiRewriteQuote
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerQuoteAiRewrite(
input: OperationInput<"customerQuoteAiRewrite">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerQuoteAiRewrite">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerQuoteAiRewrite", input, { signal });
}
Generate an editable standard MJML email design with AI at the confirmed account price
POST /v1/email-builder/ai-template
Required scope: ai:generate
Input: { body: CustomerAiEmailTemplateInput; }
Returns: AiEmailTemplateResult
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 502, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerCreateAiEmailTemplate(
input: OperationInput<"customerCreateAiEmailTemplate">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerCreateAiEmailTemplate">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerCreateAiEmailTemplate", input, { signal });
}
Generate an editable native VIP email design with AI at the confirmed member price
POST /v1/vip/email-template
Required scope: ai:generate
Input: { body: CustomerVipEmailTemplateInput; }
Returns: CustomerVipEmailTemplateResult
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 502, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerCreateVipEmailTemplate(
input: OperationInput<"customerCreateVipEmailTemplate">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerCreateVipEmailTemplate">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerCreateVipEmailTemplate", input, { signal });
}
Open a standard email design editor session for free
POST /v1/email-builder/access
Required scope: builder:write
Input: { body: CustomerEmailBuilderAccessInput; }
Returns: EmailBuilderAccess
Documented HTTP statuses: 200, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerAccessEmailBuilder(
input: OperationInput<"customerAccessEmailBuilder">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerAccessEmailBuilder">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerAccessEmailBuilder", input, { signal });
}
GET /email-builder/access/{accessId}
GET /v1/email-builder/access/{accessId}
Required scope: builder:read
Input: { query?: { designId?: string; }; path: { accessId: string; }; }
Returns: EmailBuilderActiveAccess
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetEmailBuilderAccess(
input: OperationInput<"customerGetEmailBuilderAccess">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetEmailBuilderAccess">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetEmailBuilderAccess", input, { signal });
}
DELETE /email-builder/access/{accessId}
DELETE /v1/email-builder/access/{accessId}
Required scope: builder:write
Input: { path: { accessId: string; }; }
Returns: undefined
Documented HTTP statuses: 204, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerCloseEmailBuilderAccess(
input: OperationInput<"customerCloseEmailBuilderAccess">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerCloseEmailBuilderAccess">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerCloseEmailBuilderAccess", input, { signal });
}
POST /vip/email-builder/access
POST /v1/vip/email-builder/access
Required scope: vip:builder
Input: { body: CustomerVipBuilderAccessInput; }
Returns: VipBuilderAccess
Documented HTTP statuses: 201, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerCreateVipEmailBuilderAccess(
input: OperationInput<"customerCreateVipEmailBuilderAccess">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerCreateVipEmailBuilderAccess">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerCreateVipEmailBuilderAccess", input, { signal });
}
GET /vip/email-builder/access/{accessId}
GET /v1/vip/email-builder/access/{accessId}
Required scope: builder:read
Input: { path: { accessId: string; }; }
Returns: VipBuilderAccess
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetVipEmailBuilderAccess(
input: OperationInput<"customerGetVipEmailBuilderAccess">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetVipEmailBuilderAccess">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetVipEmailBuilderAccess", input, { signal });
}
DELETE /vip/email-builder/access/{accessId}
DELETE /v1/vip/email-builder/access/{accessId}
Required scope: vip:builder
Input: { path: { accessId: string; }; }
Returns: undefined
Documented HTTP statuses: 204, 400, 401, 402, 403, 404, 409, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerDeleteVipEmailBuilderAccess(
input: OperationInput<"customerDeleteVipEmailBuilderAccess">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerDeleteVipEmailBuilderAccess">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerDeleteVipEmailBuilderAccess", input, { signal });
}
Read permanent paid-result evidence with the original account and credential
GET /customer/paid-results/{recoveryId}
Required scope: authenticated original credential
Input: { path: { recoveryId: string; }; }
Returns: { status: "pending" | "succeeded" | "failed"; operation: "customerStandardAiGenerate" | "customerVipAiGenerate" | "customerVipBuilderAccess"; settlement: { kind: "paid_result" | "no_charge" | "confirmed_refund" | "unresolved"; accountId: string; credentialId: string | null; recoveryId: string; receiptId: string; chargeMillicents?: number; refundMillicents?: number; deletedAt?: string; }; result?: { [key: string]: unknown; }; error?: { [key: string]: unknown; }; }
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetPaidResult(
input: OperationInput<"customerGetPaidResult">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetPaidResult">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetPaidResult", input, { signal });
}
Read the authenticated account and credential identity before paid dispatch
GET /customer/paid-results/identity
Required scope: authenticated credential
Input: Record<string, never>
Returns: { accountId: string; credentialId: string; }
Documented HTTP statuses: 200, 401, 403, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerPaidResultIdentity(
input: OperationInput<"customerPaidResultIdentity">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerPaidResultIdentity">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerPaidResultIdentity", input, { signal });
}
Explicitly resolve an owned paid result with the original credential and service scope
POST /customer/paid-results/{recoveryId}/resolve
Required scope: original ai:generate or vip:builder service scope
Input: { body: { action: "resolve"; reason: string; }; path: { recoveryId: string; }; }
Returns: { status: "pending" | "succeeded" | "failed"; operation: "customerStandardAiGenerate" | "customerVipAiGenerate" | "customerVipBuilderAccess"; settlement: { kind: "paid_result" | "no_charge" | "confirmed_refund" | "unresolved"; accountId: string; credentialId: string | null; recoveryId: string; receiptId: string; chargeMillicents?: number; refundMillicents?: number; deletedAt?: string; }; result?: { [key: string]: unknown; }; error?: { [key: string]: unknown; }; }
Documented HTTP statuses: 200, 400, 401, 403, 404, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerResolvePaidResult(
input: OperationInput<"customerResolvePaidResult">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerResolvePaidResult">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerResolvePaidResult", input, { signal });
}
Import and compile a standard MJML design without saving or sending
POST /v1/email-builder/import
Required scope: builder:write
Input: { body: CustomerStandardBuilderInput; }
Returns: CustomerStandardBuilderImportResult
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerStandardBuilderImport(
input: OperationInput<"customerStandardBuilderImport">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerStandardBuilderImport">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerStandardBuilderImport", input, { signal });
}
Validate and compile a standard MJML design without saving or sending
POST /v1/email-builder/validate
Required scope: builder:write
Input: { body: CustomerStandardBuilderInput; }
Returns: CustomerStandardBuilderValidateResult
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerStandardBuilderValidate(
input: OperationInput<"customerStandardBuilderValidate">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerStandardBuilderValidate">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerStandardBuilderValidate", input, { signal });
}
Compile a standard MJML design to HTML without saving or sending
POST /v1/email-builder/compile
Required scope: builder:write
Input: { body: CustomerStandardBuilderInput; }
Returns: CustomerStandardBuilderCompileResult
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerStandardBuilderCompile(
input: OperationInput<"customerStandardBuilderCompile">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerStandardBuilderCompile">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerStandardBuilderCompile", input, { signal });
}
Export a standard MJML design as HTML, MJML or ZIP without sending
POST /v1/email-builder/export
Required scope: builder:write
Input: { body: CustomerStandardBuilderInput; }
Returns: CustomerStandardBuilderExportResult
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerStandardBuilderExport(
input: OperationInput<"customerStandardBuilderExport">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerStandardBuilderExport">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerStandardBuilderExport", input, { signal });
}
Import and compile a native VIP design with active membership and owned open access
POST /v1/vip/email-builder/import
Required scope: vip:builder
Input: { body: CustomerNativeBuilderInput; }
Returns: CustomerNativeBuilderImportResult
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerNativeBuilderImport(
input: OperationInput<"customerNativeBuilderImport">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerNativeBuilderImport">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerNativeBuilderImport", input, { signal });
}
Validate and compile a native VIP design with active membership and owned open access
POST /v1/vip/email-builder/validate
Required scope: vip:builder
Input: { body: CustomerNativeBuilderInput; }
Returns: CustomerNativeBuilderValidateResult
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerNativeBuilderValidate(
input: OperationInput<"customerNativeBuilderValidate">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerNativeBuilderValidate">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerNativeBuilderValidate", input, { signal });
}
Compile a native VIP design to HTML with active membership and owned open access
POST /v1/vip/email-builder/compile
Required scope: vip:builder
Input: { body: CustomerNativeBuilderInput; }
Returns: CustomerNativeBuilderCompileResult
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerNativeBuilderCompile(
input: OperationInput<"customerNativeBuilderCompile">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerNativeBuilderCompile">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerNativeBuilderCompile", input, { signal });
}
Export a native VIP design as HTML or a three-variant HTML ZIP without sending
POST /v1/vip/email-builder/export
Required scope: vip:builder
Input: { body: CustomerNativeBuilderInput; }
Returns: CustomerNativeBuilderExportResult
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerNativeBuilderExport(
input: OperationInput<"customerNativeBuilderExport">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerNativeBuilderExport">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerNativeBuilderExport", input, { signal });
}
Launch a one-time standard or entitled native VIP hosted editor handoff
POST /v1/email-builder/hosted-handoffs
Required scope: builder:write
Input: { body: CustomerHostedBuilderHandoffInput; }
Returns: CustomerHostedBuilderHandoff
Documented HTTP statuses: 201, 400, 401, 403, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerCreateHostedBuilderHandoff(
input: OperationInput<"customerCreateHostedBuilderHandoff">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerCreateHostedBuilderHandoff">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerCreateHostedBuilderHandoff", input, { signal });
}
List Vip Builder Templates
GET /v1/vip/email-builder/templates
Required scope: vip:read
Input: Record<string, never>
Returns: CustomerVipTemplateCatalog
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerListVipBuilderTemplates(
input: OperationInput<"customerListVipBuilderTemplates">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerListVipBuilderTemplates">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerListVipBuilderTemplates", input, { signal });
}
Get Vip Builder Template
GET /v1/vip/email-builder/templates/{templateId}
Required scope: vip:read
Input: { path: { templateId: string; }; }
Returns: CustomerVipTemplateDocument
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetVipBuilderTemplate(
input: OperationInput<"customerGetVipBuilderTemplate">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetVipBuilderTemplate">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetVipBuilderTemplate", input, { signal });
}
List Standard Builder Templates
GET /v1/email-builder/templates
Required scope: catalog:read
Input: Record<string, never>
Returns: CustomerStandardTemplateCatalog
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerListStandardBuilderTemplates(
input: OperationInput<"customerListStandardBuilderTemplates">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerListStandardBuilderTemplates">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerListStandardBuilderTemplates", input, { signal });
}
Get Standard Builder Template
GET /v1/email-builder/templates/{templateId}
Required scope: catalog:read
Input: { path: { templateId: string; }; }
Returns: CustomerStandardTemplateDetail
Documented HTTP statuses: 200, 400, 401, 403, 404, 413, 429, 503
Parameters, schemas and HTTP examples
import type { OperationInput, OperationResponse } from "@sendrepute/node";
async function customerGetStandardBuilderTemplate(
input: OperationInput<"customerGetStandardBuilderTemplate">,
confirmed: boolean,
signal?: AbortSignal,
): Promise<OperationResponse<"customerGetStandardBuilderTemplate">> {
if (confirmed !== true) throw new Error("Explicit action confirmation required");
return client.request("customerGetStandardBuilderTemplate", input, { signal });
}
Self-hosted n8n node
0.1.0
Requires Node.js 20.19+ and a patched self-hosted n8n installation supplying n8n-workflow >=2.39.3 <3. Do not force-install into an older incompatible host. Install the downloaded tarball in your custom-node directory and restart n8n. This unpublished node is not available through n8n Cloud or npm-name community installation.
Paid consent is off by default. Each consenting item performs one classification request with no automatic retries. Results are namespaced under sendrepute. Use an IF gate on sendrepute.allowed before sending, and check failure status separately. Advisory and blocking modes return explicit decisions. The node itself does not send mail.
Download n8n tarball
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Run on the self-hosted n8n host, then restart its n8n service using your normal process manager. Confirm SendRepute appears in the node picker. Import the extracted package/examples/classify-email.workflow.json from the n8n editor. npm-name Community nodes installation and n8n Cloud are not supported by this unpublished package.
mkdir -p ~/.n8n/nodes
cd ~/.n8n/nodes
curl -fLO https://www.sendrepute.com/downloads/sendrepute-n8n.tgz
npm install ./sendrepute-n8n.tgz
tar -xzf sendrepute-n8n.tgz package/examples/classify-email.workflow.json
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/n8n-nodes-sendrepute.git
cd n8n-nodes-sendrepute
npm ci
npm run pack:check
npm pack --ignore-scripts
archive="$PWD/n8n-nodes-sendrepute-0.1.0.tgz"
mkdir -p ~/.n8n/nodes
cd ~/.n8n/nodes
npm install "$archive"
2. Configure securely
Create a SendRepute API credential with a classify-scoped customer key in n8n credentials storage. Never place it in workflow JSON or expressions. The JSON below shows node parameters, not a complete importable workflow. Map sender display name, subject and body; choose advisory/blocking, threshold and open/closed failure policy. Review pricing before switching paidConsent to true. Every consenting item performs at most one request.
{
"operation": "classify",
"paidConsent": false,
"sender": "={{ $json.sender }}",
"subject": "={{ $json.subject }}",
"body": "={{ $json.body }}",
"decisionMode": "blocking",
"threshold": 0.8,
"failurePolicy": "closed"
}
3. Use it deliberately
Place an IF node immediately after SendRepute and use this boolean condition. Connect only the true output to your existing email node; route false to review or stop. Inspect analysisStatus separately even when allowed is true. The included workflow starts with paid consent disabled and contains no credentials. SendRepute itself never sends mail.
{{ $json.sendrepute.allowed === true }}
Results, failures and limits
Successful results replace the sendrepute namespace with analysisStatus, decision, allowed, recommendation, validated score and billing fields. Failures omit spam scores and return sanitized failureCategory/errorCode. Closed failures block; open failures allow but mark analysisStatus as failed. Advisory successes always allow regardless of recommendation. Consent-off returns not_run. There are no retries, recipients, attachments, rewrites, model selector or custom endpoints. The updated source dependency audit reported zero findings; this is a point-in-time result, not security certification. Keep the self-hosted runtime patched and review SECURITY.md before installation.
Laravel integration
0.1.0
Targets PHP 8.2+ and Laravel 12–13. Install the ZIP using a local Composer artifact repository, or extract it and configure a Composer path repository as described in the included README. No Packagist publication is claimed.
Paid consent and the mail hook are disabled by default. Even when enabled, each message must explicitly opt in with X-SendRepute-Classify: yes. The header is removed before delivery. Advisory and blocking modes have independent failure policies; password resets and transactional mail remain untouched unless deliberately opted in.
Download Laravel ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Run inside your Laravel application. These commands extract the download and register a Composer path repository; this is not a Packagist installation. Package discovery registers the provider, and vendor:publish creates config/sendrepute.php. Keep the extracted package directory available to Composer. An artifact repository is another option documented in the README.
mkdir -p packages
curl -fL https://www.sendrepute.com/downloads/sendrepute-laravel.zip -o packages/sendrepute-laravel.zip
unzip packages/sendrepute-laravel.zip -d packages
composer config repositories.sendrepute path ./packages/sendrepute-laravel
composer require sendrepute/laravel:@dev
php artisan vendor:publish --tag=sendrepute-config
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
composer config repositories.sendrepute vcs https://github.com/sendrepute/sendrepute-laravel
composer require sendrepute/laravel:dev-main
php artisan vendor:publish --tag=sendrepute-config
2. Configure securely
Store SENDREPUTE_API_KEY in server secrets. The base URL ends in /api; the client appends /v1/classify. Exact trusted-host matching and verified HTTPS are required. Both switches shown remain off until you review pricing and explicitly set them to true. In config/sendrepute.php choose mail.mode, mail.spam_probability_threshold and mail.failure_policy independently. The default is advisory with allow on failure.
SENDREPUTE_API_BASE_URL=https://www.sendrepute.com/api
SENDREPUTE_TRUSTED_HOSTS=www.sendrepute.com
SENDREPUTE_PAID_ANALYSIS_CONSENT=false
SENDREPUTE_MAIL_ENABLED=false
3. Use it deliberately
Add the exact opt-in header only to deliberately selected Mailable classes, never a global mail callback. Both global switches and the per-message header are needed for the automatic hook. The header is removed before delivery. Keep password resets and critical notifications out of automatic blocking unless explicitly tested. Manual classification can instead resolve the Classifier contract and grant consent per call, as shown.
// Inside your deliberately opted-in Mailable:
public function headers(): \Illuminate\Mail\Mailables\Headers
{
return new \Illuminate\Mail\Mailables\Headers(text: [
'X-SendRepute-Classify' => 'yes',
]);
}
// Or classify manually inside an authenticated, explicitly confirmed action:
function classifyAfterConsent(bool $confirmed, string $subject, string $body): \SendRepute\Laravel\ClassificationResult
{
if (!$confirmed) {
throw new \RuntimeException('Paid consent required');
}
return app(\SendRepute\Laravel\Contracts\Classifier::class)->classify(
sender: 'Example Company',
subject: $subject,
body: $body,
paidAnalysisConsent: true,
);
}
API and method reference
Resolve the Classifier interface from Laravel's container. classify(string sender, string subject, string body, ?string model = null, bool paidAnalysisConsent = false) returns ClassificationResult. Its public fields are requestId, model, label, spamProbability, confidence, replayed and chargedMillicents. SendReputeException supplies sanitized category, HTTP status, API code and request ID. The automatic hook is AnalyzeOutgoingMessage on MessageSending and its safe diagnostic is ClassificationOutcome. This integration supports classification only, not account administration, payments, builders or AI rewrite.
Results, failures and limits
ClassificationResult contains validated result and billing data. The MessageSending hook returns false to cancel a blocked message; cancellation is not an SMTP error or a MessageSent event. ClassificationOutcome reports only action, score and sanitized failure metadata, never message content. Failure policy covers malformed input/response, authentication, balance, rate limits and transport problems. No retries or queue are added. A named sender and in-memory text or HTML body are required.
Mautic draft preflight
0.1.0
Targets single-web-node Mautic 5.x installations with PHP 8.1+ and ext-curl. Mautic 4, Mautic 6 and multi-node clusters are not supported. Extract SendReputeBundle into your plugins directory, reload plugins and clear the cache following the included README. Configure the credential and explicitly confirm local-flock lock mode in the server environment.
Administrator-initiated, paid advisory analysis of a saved draft only. Global opt-in, entity access checks, CSRF validation and a one-use confirmation protect each request. It does not send, rewrite or block emails and has no send-time enforcement. Recipient substitutions remain unexpanded; save editor changes first.
Download Mautic ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Run from your Mautic root with the same PHP user and environment as the web application, or extract the ZIP through your deployment process before reloading plugins. Requires Mautic 5.x, PHP 8.1+, ext-curl and a single Linux/POSIX web node. Mautic 4/6 and multi-node clusters are unsupported; no live patch-by-patch installation certification is claimed.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-mautic.zip
unzip sendrepute-mautic.zip -d plugins
php bin/console mautic:plugins:reload
php bin/console cache:clear
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
git clone https://github.com/sendrepute/sendrepute-mautic.git
cd sendrepute-mautic
python3 package.py
2. Configure securely
Create the shown persistent ledger directory outside the web root, owned by the PHP user with mode 0700. Do not use /tmp, ephemeral containers, symlinks or uncertain network storage. Store SENDREPUTE_API_KEY server-side. Confirm local-flock only when one web node provides shared process locking. Global paid analysis stays disabled at 0; set it to 1 only after reviewing pricing and limits. No browser field may provide the credential or endpoint.
SENDREPUTE_MAUTIC_PAID_ANALYSIS_ENABLED=0
SENDREPUTE_MAUTIC_ATOMIC_LOCK_MODE=local-flock
SENDREPUTE_MAUTIC_LEDGER_DIR=/var/lib/mautic/sendrepute-ledger
3. Use it deliberately
Save editor changes first. As a real Mautic administrator with access to that email, open the saved draft and choose SendRepute preflight. Review the confirmation and explicitly accept the paid operation. The request needs CSRF validation and a ten-minute, one-use intent bound to the saved content. Persistent locking and a content-free ledger prevent duplicate concurrent spending on the supported single node.
Results, failures and limits
Displays validated probability, label, confidence and actual billed amount or receipt replay. Failures display no spam decision and are not automatically retried. Only saved sender display name, subject and body are analyzed; contact substitutions remain unexpanded. The plugin does not rewrite drafts, send email, block campaigns or enforce a send-time policy. A saved-draft review cannot certify the eventual recipient-rendered message.
Python client and Django backend
0.1.0
Requires Python 3.9+. Extract the source ZIP and install its directory with pip. The generic server client uses the standard library; Django is an optional dependency for the explicit email backend. This package is not published on PyPI.
Paid consent defaults to off. The Django wrapper preserves the original transport and message objects. It analyzes one bounded string combining the primary body and inline text/plain and text/html alternatives, not attachments. Blocking mode rejects unsupported or oversized displayed content. Authentication failures block by default even with an allow policy; choose critical-mail behavior deliberately.
Download Python source ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Use a virtual environment. The generic client is standard-library-only; the final command adds the optional Django dependency and is unnecessary for Flask, FastAPI or other generic server use. The package is installed from the downloaded source directory, not PyPI. Python 3.9+ is the package minimum; choose Python/Django versions supported together.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-python.zip
unzip sendrepute-python.zip
python -m venv .venv
. .venv/bin/activate
python -m pip install ./sendrepute-python
python -m pip install './sendrepute-python[django]'
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
python -m pip install "sendrepute @ git+https://github.com/sendrepute/sendrepute-python.git@7d54935c4ae2db136800231136e4ea28d63118db"
python -m pip install "sendrepute[django] @ git+https://github.com/sendrepute/sendrepute-python.git@7d54935c4ae2db136800231136e4ea28d63118db"
2. Configure securely
Inject SENDREPUTE_API_KEY via server secrets. The generic client defaults to the canonical hosted endpoint, verified HTTPS, no redirects and no retries. Client consent defaults off; the example grants per-call consent only after checking confirmed. Endpoint overrides need an explicit HTTPS origin allowlist. The returned dictionary contains validated result and billing data, not a send decision.
import os
from sendrepute import SendReputeClient, SendReputeError
client = SendReputeClient(api_key=os.environ["SENDREPUTE_API_KEY"])
def classify_after_consent(sender, subject, body, confirmed=False):
if confirmed is not True:
raise ValueError("Paid consent required")
try:
return client.classify(
sender=sender, subject=subject, body=body,
paid_analysis_consent=True,
)
except SendReputeError as error:
# Safe metadata only; do not log message content or response bodies.
print(error.code, error.status, error.request_id)
raise
Django email backend
Preserve your existing backend in SENDREPUTE_ORIGINAL_EMAIL_BACKEND and keep its normal SMTP settings. The example keeps paid consent off; set it to True only after pricing review. Advisory allows successful analyses; blocking compares to SENDREPUTE_SPAM_THRESHOLD. Choose the independent failure policy deliberately. Authentication errors block by default even under allow. The example follows README defaults and is not a recommendation to fail open for critical mail.
# Django settings.py
import os
EMAIL_BACKEND = "sendrepute.django.SendReputeEmailBackend"
SENDREPUTE_ORIGINAL_EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
SENDREPUTE_API_KEY = os.environ["SENDREPUTE_API_KEY"]
SENDREPUTE_PAID_ANALYSIS_CONSENT = False
SENDREPUTE_POLICY_MODE = "advisory"
SENDREPUTE_SPAM_THRESHOLD = 0.90
SENDREPUTE_FAILURE_POLICY = "allow"
SENDREPUTE_ALLOW_AUTH_FAILURE = False
SENDREPUTE_TIMEOUT = 10
3. Use it deliberately
This function sends only when called. With the Django wrapper configured and paid consent enabled, the original backend receives the original message objects unchanged. The classifier receives one bounded string combining the primary body with inline text/plain and text/html alternatives; attachments and recipients are not separate inputs. Render templates before calling. Use a local test backend first, then your deliberately configured real transport.
from django.core.mail import EmailMultiAlternatives
def send_reviewed_message(recipient):
message = EmailMultiAlternatives(
subject="Your requested summary",
body="Here is the summary you requested.",
from_email="Example Team <team@example.com>",
to=[recipient],
)
message.attach_alternative(
"<p>Here is the summary you requested.</p>", "text/html"
)
return message.send()
API and method reference
The public constructor is SendReputeClient(api_key, endpoint, allowed_origins, timeout, paid_analysis_consent), with all but api_key passed by keyword. timeout must be greater than zero and at most 30 seconds. classify requires keyword sender, subject and body; model and per-call paid_analysis_consent are optional. Sender is 1–320 characters, subject 1–998 and body 1–524,288, with a separate encoded request bound. The returned dict contains requestId, model, result and billing; result includes label, spamProbability, confidence, reasons and optional contentAudit. billing contains chargedMillicents and replayed. Errors include ConsentRequiredError, AuthenticationError, BalanceError, RateLimitError, TransportError and InvalidResponseError, all under SendReputeError. Invalid configuration can raise ValueError. The Django backend exposes open(), close() and send_messages(email_messages), returning the original backend's sent count; it adds no generic API, builder, rewrite or payment methods.
Results, failures and limits
Blocking rejects unsupported or oversized displayed content instead of analyzing only a safer subset. Authentication failures require a separate explicit override to allow. Other errors follow the chosen allow/block policy; fail_silently controls whether blocked failures are raised or skipped. The wrapper does not queue, retry, swap transports, inspect attachments or render templates. The generic client raises sanitized SendReputeError subclasses with code/status/request_id; do not log message bodies.
Go classification client
0.1.0
Requires Go 1.22+. The standard-library-only client supports classification, not email transport. Choose the downloadable source ZIP with a local module replacement, or the verified public module installation shown under the source alternative.
Standard-library-only, server-side classification with explicit paid consent, bounded requests, verified HTTPS, refused redirects and no retries. It does not send email or make send/block decisions. Your application must deliberately choose thresholds and failure behavior, especially for critical transactional mail.
Download Go source ZIP
Public source repository
Full README and examples
Security notes and known limitations
1. Install
Extract the source into your existing Go application's directory and run the module commands there. The local replacement points at the downloaded module; move or adjust that path if your project layout differs. Run go mod init with your own module name first only when creating a new application. No external runtime modules are required by this client.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-go.zip
unzip sendrepute-go.zip
# Run inside your existing application's module:
go mod edit -require=github.com/sendrepute/sendrepute-go@v0.0.0
go mod edit -replace=github.com/sendrepute/sendrepute-go=./sendrepute-go-v0.1.0
go mod tidy
Alternative: install from public source
Use this source route instead of the website download instructions above. The repository README explains the remaining activation and configuration steps; building a ZIP alone does not install a plugin. For Python, the second command adds optional Django support. Keep credentials in server secrets and review the security notes before enabling paid features. Only Node is on npm; a public GitHub repository does not imply WordPress.org, n8n Cloud, Packagist or PyPI publication.
go get github.com/sendrepute/sendrepute-go@bfd656f829618348232da506225a5d92587d48e2
2. Configure securely
Inject SENDREPUTE_API_KEY from server secrets. The function shown performs no work until called with confirmed=true; that call can incur a paid classification. It sets a ten-second context and uses the canonical HTTPS endpoint. Client consent defaults off; the final true argument grants consent for this one request. An endpoint override requires an explicit AllowedOrigins entry; redirects are refused.
package integration
import (
"context"
"errors"
"os"
"time"
sendrepute "github.com/sendrepute/sendrepute-go"
)
func Analyze(subject, body string, confirmed bool) error {
if !confirmed {
return errors.New("paid consent required")
}
client, err := sendrepute.NewClient(sendrepute.Config{
APIKey: os.Getenv("SENDREPUTE_API_KEY"),
})
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
result, err := client.Classify(ctx, sendrepute.ClassificationInput{
Sender: "Example Team", Subject: subject, Body: body,
}, true)
if err != nil {
return err
}
if result.Result.SpamProbability >= 0.90 {
return errors.New("review required")
}
return nil
}
3. Use it deliberately
Call Analyze from your authenticated application only after pricing review and explicit consent. The 0.90 threshold and review error are example application policy, not SDK defaults. Decide whether errors mean defer, allow or fail closed before connecting any sending code. The client returns a typed result with Result.SpamProbability and billing fields; it never sends email or makes delivery decisions itself.
API and method reference
NewClient(Config) returns (*Client, error). Config accepts APIKey, Endpoint, AllowedOrigins, Timeout and PaidAnalysisConsent. Classify(ctx, ClassificationInput, consent) returns (*ClassificationResponse, error). Input fields are Sender, Subject, Body and optional Model. Sender is 1–320 runes, subject 1–998 runes and body at most 524,288 UTF-8 bytes. The typed response contains RequestID, Model, Result and Billing; Billing exposes ChargedMillicents and Replayed. Result includes Label, SpamProbability, Confidence, Reasons, FlaggedTerms and optional ContentAudit. Use errors.As to inspect *Error safely; configuration and API failures remain errors, not spam scores. No account, payment, builder or rewrite methods exist.
Results, failures and limits
One invocation makes at most one paid HTTP attempt with no retries. Errors expose a safe category, restricted code/request ID and status, never credentials, bodies or network details. Context duration, request and response sizes are bounded; malformed responses are rejected rather than converted to scores. The client has no MIME parsing, rendering, recipients, attachments, queue, builder, rewrite or SMTP capabilities. Choose model explicitly only if needed; otherwise the account default applies.
listmonk HTTP Messenger
0.1.0
An unpublished local source package for Node.js 20+ targeting listmonk 6.2.0's Custom HTTP Messenger interface. This external service owns downstream SMTP delivery after classification; it is not an in-process plugin or an SMTP preflight proxy. Verification is isolated and offline, not an installed listmonk deployment or real SMTP-provider test.
Both paid switches default off. The messenger accepts one fully rendered body, rejects attachments, checks fresh pricing, and requires the strict Inbox result: label inbox, spam probability at most 0.12, and zero flagged terms. It then builds and sends that same inspected body over its configured SMTP connection. Durable receipts prevent automatic repeats after blocked, failed, in-progress, or uncertain outcomes.
Download unpublished listmonk source ZIP
1. Install
Extract this unpublished website source ZIP on the dedicated messenger host. Review README.md and SECURITY.md, copy the example environment, and syntax-check the server entry point before configuration. The downloadable allowlisted artifact intentionally excludes the repository test suite. There are no third-party runtime packages. This is not a listmonk marketplace or in-process installation.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-listmonk.zip
unzip sendrepute-listmonk.zip
cd sendrepute-listmonk
cp config.example.env .env
node --check src/server.mjs
2. Configure securely
Use a dedicated unprivileged account and durable local state directory with mode 0700. Keep all three shown safety switches false until pricing and the non-atomic price limitation are accepted. Store SendRepute, messenger Basic Auth, and downstream SMTP credentials only in server secrets. Terminate HTTPS at a trusted reverse proxy.
SENDREPUTE_ENABLED=false
SENDREPUTE_PAID_CONSENT=false
SENDREPUTE_ALLOW_NONATOMIC_PRICE_CONFIRMATION=false
SENDREPUTE_CONFIRMED_MAX_PRICE_MILLICENTS=
STATE_DIRECTORY=/var/lib/sendrepute-listmonk
SMTP_HOST=smtp.example.com
SMTP_PORT=465
SMTP_SECURE=true
3. Use it deliberately
Expose only POST /v1/listmonk behind HTTPS and dedicated Basic Auth. In listmonk Settings > Messengers, add its URL as a Custom HTTP Messenger, choose zero retries, and select it only for campaigns that should be inspected and delivered. Do not also select listmonk SMTP: this service performs the downstream SMTP send itself.
Custom HTTP Messenger URL: https://messenger.example.com/v1/listmonk
Authentication: dedicated Basic Auth username and password
Retries: 0
Select this messenger only. Do not also select SMTP for the campaign.
Results, failures and limits
A delivered duplicate returns success without another classification or send. Every blocked, failed, inspecting, sending, or uncertain receipt refuses another send. After an uncertain SMTP outcome, reconcile provider logs and listmonk context manually; never delete a receipt merely to force a retry. The current pricing check is fresh but non-atomic because classification accepts no expectedPriceMillicents field.
Mailcoach Self-Hosted adapter
0.1.0
An unpublished local Composer package targeting Mailcoach Self-Hosted v10 on Laravel 12. The licensed spatie/laravel-mailcoach v10 core is not available in this workspace, so this package does not claim an installed Mailcoach v10 end-to-end test. Real Laravel 12 Mailer tests cover the documented cancellable MessageSending event; a license holder must verify every exact Mailcoach sending path before production.
The enabled, paid-consent, and current-pricing acknowledgement switches all default off. Once enabled, the hook applies to every message through that Laravel mailer, not only Mailcoach-named routes. It analyzes the already-rendered Symfony Email alternatives and can cancel transport. Fail-closed is the default; allowing analysis failures is a separate deliberate policy.
Download experimental Mailcoach source ZIP
1. Install
Place the downloaded unpublished ZIP in a private Composer artifact directory accessible to the licensed Mailcoach application. Register that local artifact repository, require the 0.1 line, commit the consuming lockfile, and optionally publish configuration. This is not a Packagist installation. A license holder must run verification against the exact Mailcoach Self-Hosted v10 release.
mkdir -p packages
curl -fL https://www.sendrepute.com/downloads/sendrepute-mailcoach.zip -o packages/sendrepute-mailcoach.zip
composer config repositories.sendrepute artifact packages
composer require sendrepute/mailcoach:^0.1
php artisan vendor:publish --tag=sendrepute-mailcoach-config
2. Configure securely
Keep all three switches false initially. Store the API key in server secrets and configure an account-side spend cap. The current classify operation has no atomic expectedPriceMillicents guard, so the third switch explicitly accepts current API pricing rather than promising a locked quote. Configure threshold and allow/block failure policy independently.
SENDREPUTE_MAILCOACH_ENABLED=false
SENDREPUTE_MAILCOACH_PAID_CONSENT=false
SENDREPUTE_MAILCOACH_ACCEPT_CURRENT_API_PRICING=false
SENDREPUTE_API_BASE_URL=https://www.sendrepute.com/api
3. Use it deliberately
Package discovery registers a Laravel MessageSending listener. There is no per-campaign call in application code: when deliberately enabled in a dedicated Mailcoach installation, it inspects every Symfony Email sent through that Laravel mailer immediately before transport. In a mixed Laravel application, host-application mail is covered too.
Results, failures and limits
The adapter submits sender display name, subject, and each non-empty in-memory text/plain or text/html alternative while excluding recipients, addresses, attachments, envelope data, and raw MIME. Missing or unsupported content, malformed responses, and API failures block by default. Offline core tests exercise real Laravel Mailer cancellation, but licensed Mailcoach campaign, automation, transactional, and test-message routes remain not verified.
Brevo controlled send flow
0.1.0
An unpublished local Node.js 20+ source package implementing an explicit server-side send API around Brevo's transactional POST /v3/smtp/email operation. It does not intercept Brevo dashboard sends, campaigns, automations, SMTP relay, or calls through other SDKs. Tests are controlled and offline; they do not certify a live Brevo account.
Paid consent defaults off. Only fixed inline text and HTML messages are accepted; remote templates, parameters, scheduled sends, message versions, and URL-backed content are rejected. The exact immutable inspected snapshot is sent to Brevo. A durable sendKey ledger blocks duplicate and ambiguous retries, and uncertain provider outcomes require operator reconciliation.
Download unpublished Brevo source ZIP
1. Install
Extract the unpublished source ZIP into a server application, review its README and security notes, and syntax-check src/index.mjs. The downloadable allowlisted artifact intentionally excludes the repository test suite. Import SendReputeBrevo from src/index.mjs; this is not an npm or Brevo marketplace installation. Node.js 20+ is required and there are no runtime dependencies.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-brevo.zip
unzip sendrepute-brevo.zip
cd sendrepute-brevo
node --check src/index.mjs
2. Configure securely
Keep paidConsent false until current pricing and the non-atomic price limitation are accepted. Keep both API keys in server secrets and use a private persistent ledger directory on durable single-host storage. expectedPriceMillicents must equal the freshly fetched maximum, but the classify debit cannot yet atomically enforce that value.
const integration = new SendReputeBrevo({
sendreputeApiKey: process.env.SENDREPUTE_API_KEY,
brevoApiKey: process.env.BREVO_API_KEY,
paidConsent: false,
expectedPriceMillicents: approvedMaximum,
ledgerDirectory: "/var/lib/my-app/sendrepute-brevo",
});
3. Use it deliberately
Call send only from the controlled server path that should both classify and deliver. Reuse one stable sendKey for every attempt of the same intended email. Supply fixed inline content; do not supply Brevo template IDs, mutable parameters, scheduling, or message versions. Sends made elsewhere bypass this wrapper completely.
await integration.send({
sendKey: durableBusinessEventId,
message: {
sender: { name: "Example Shop", email: "orders@example.com" },
to: [{ email: recipient }],
subject,
textContent,
htmlContent,
},
});
Results, failures and limits
An Inbox result within threshold permits one Brevo transactional API request for the same immutable snapshot. The ledger changes to delivery-unknown before provider dispatch. Timeouts, disconnects, malformed successes, crashes, and provider rejections are never automatically retried; reconcile them against Brevo records before any manual decision.
BigMailer controlled send flow
0.1.0
An unpublished local Node.js 24+ wrapper for explicit BigMailer transactional API calls. It does not install into BigMailer or intercept dashboard and unrelated API sends. Because BigMailer owns remotely editable campaign content, the wrapper cannot prove that the campaign remained equal to the caller-provided render snapshot between review and delivery.
Enabled, paid consent, and the remote-template limitation acknowledgement all default off. The caller must supply and hash a complete render snapshot, freeze the matching remote campaign operationally, and provide a durable delivery key. Pricing is rechecked before classification, but the current classification API has no atomic expected-price field. Duplicate, blocked, rejected, and ambiguous delivery states never resend automatically.
Download experimental BigMailer source ZIP
1. Install
Extract this unpublished source ZIP into the controlled Node.js 24+ server application and review README.md and SECURITY.md. Import the wrapper and file delivery store directly from src. This is not an npm or BigMailer marketplace installation and has no third-party runtime dependencies.
curl -fLO https://www.sendrepute.com/downloads/sendrepute-bigmailer.zip
unzip sendrepute-bigmailer.zip
cd sendrepute-bigmailer
node --check src/index.mjs
node --check src/file-delivery-store.mjs
2. Configure securely
Keep enabled, paidConsent, and remoteTemplateSnapshotLimitationAcknowledged false until review. Store API keys, brand and campaign UUIDs only server-side. Put FileDeliveryStore on private durable storage. Copy freshly reviewed pricing into expectedPricing, understanding that the current classify API cannot atomically lock it.
const integration = createBigMailerIntegration({
enabled: false,
paidConsent: false,
remoteTemplateSnapshotLimitationAcknowledged: false,
sendReputeApiKey: process.env.SENDREPUTE_API_KEY,
bigMailerApiKey: process.env.BIGMAILER_API_KEY,
brandId,
campaignId,
expectedPricing,
deliveryStore: new FileDeliveryStore("/var/lib/my-app/bigmailer-deliveries.json"),
});
3. Use it deliberately
For each controlled API send, provide one stable deliveryKey, all displayed text/plain and text/html alternatives, the exact render snapshot and snapshotDigest(snapshot). Acknowledge the remote-template limitation only when an operational control freezes the BigMailer campaign revision matching that snapshot. Dashboard and unrelated API sends bypass this wrapper.
await integration.send({
deliveryKey: durableBusinessEventId,
snapshot,
snapshotSha256: snapshotDigest(snapshot),
email: recipient,
variables,
});
Results, failures and limits
The file store reserves the delivery key before classification. Duplicate, conflict, block, rejection, and ambiguous delivery outcomes cannot send again automatically. BigMailer's send endpoint accepts merge data rather than the inspected body, so successful classification is not proof that mutable remote campaign content still matches; use another provider when exact coupling is required.
Privacy and paid operations
Analysis sends sender display name, subject and message body to SendRepute. Recipients and attachments are not transmitted separately, but content included in the body is transmitted. Keep credentials secret and disable request/body logging. No inbox-placement or delivery guarantee.
Classification is paid. Read current pricing and your account spend limits before granting consent. An identical account/content/model request may replay a receipt within 24 hours; changed content or model can incur a new charge. Do not assume a retry is free. AI rewrite requires a maximum-charge quote for the selected parent receipt, mode and terms before paid submission; poll for an in-progress receipt and recover completed results with the original request ID rather than starting another request. Rewrite All can verify one exact final rendered draft without another debit. AI template generation and native VIP access are separately priced; standard builder processing is free. No analysis, rewrite or builder result guarantees delivery, inbox placement or compliance.
Offline validation is not certification of every framework, plugin or transport version. Read the included installation and security instructions, keep paid analysis disabled until deliberately configured, and test your chosen failure policy before enabling it for critical mail.
Review pricing
Customer API reference
Ask integration support