pub struct Service { /* private fields */ }Implementations§
Source§impl Service
impl Service
Sourcepub async fn build(cfg: CoreConfig, sink: Arc<dyn EventSink>) -> Result<Service>
pub async fn build(cfg: CoreConfig, sink: Arc<dyn EventSink>) -> Result<Service>
Build the engine: open the DB, migrate, spawn workers, prepare
listeners. Doesn’t bind any sockets — call Service::start_all.
Sourcepub fn subscribe(&self) -> Receiver<CoreEvent>
pub fn subscribe(&self) -> Receiver<CoreEvent>
Subscribe to engine events. Each call returns a fresh
broadcast::Receiver; consumers that lag behind by more than
the channel capacity (currently 1024) will receive Lagged
errors and must reconnect. This is the canonical way for the
CLI tail, the SSE endpoint, the wait_for_email primitive,
and external consumers to observe events.
Sourcepub fn set_log_level_controller(&self, ctl: Arc<dyn Fn(bool) + Send + Sync>)
pub fn set_log_level_controller(&self, ctl: Arc<dyn Fn(bool) + Send + Sync>)
Install a callback the engine invokes when the persisted
AdvancedPrefs.debug_logging value changes (and once at
start_all to honor the initial value). The embedder owns the
tracing_subscriber stack; this lets the engine drive a filter
reload without depending on the subscriber implementation.
Idempotent — calling it again replaces the previous controller.
Sourcepub async fn start_all(&self) -> Result<()>
pub async fn start_all(&self) -> Result<()>
Start every persisted mailbox’s listener + the HTTP API. Idempotent.
Sourcepub async fn restart_http(&self) -> Result<()>
pub async fn restart_http(&self) -> Result<()>
Tear down the running HTTP listener (if any) and start a fresh
one with whatever’s currently persisted in BackendSettings.
Used by update_settings to apply network-pref changes live
without requiring an app restart.
No-op when the service hasn’t reached start_all yet — the
boot path will pick up the new settings when it gets there. If
the rebind fails, the previous listener stays torn down and the
error is propagated so the caller can revert the patch.
pub async fn stop_all(&self) -> Result<()>
pub fn status(&self) -> ServerStatus
Sourcepub fn http_addr(&self) -> Option<SocketAddr>
pub fn http_addr(&self) -> Option<SocketAddr>
The HTTP API’s bound socket address, if the server is running.
Sourcepub fn mailbox_addr(&self, mailbox_id: &str) -> Option<SocketAddr>
pub fn mailbox_addr(&self, mailbox_id: &str) -> Option<SocketAddr>
The bound SMTP socket address for a given mailbox listener.
pub fn handle(&self) -> ServiceHandle
pub fn config(&self) -> &CoreConfig
pub async fn list_mailboxes( &self, project_id: Option<&str>, ) -> Result<Vec<Mailbox>>
pub async fn get_mailbox(&self, id: &str) -> Result<Mailbox>
pub async fn create_mailbox(&self, input: CreateMailboxInput) -> Result<Mailbox>
pub async fn update_mailbox( &self, id: &str, patch: UpdateMailboxInput, ) -> Result<Mailbox>
pub async fn delete_mailbox(&self, id: &str) -> Result<()>
Sourcepub async fn suggest_mailbox_port(&self, start: Option<u16>) -> Result<u16>
pub async fn suggest_mailbox_port(&self, start: Option<u16>) -> Result<u16>
Suggest a free SMTP port for a new mailbox. Walks upward from
start (defaulting to 1025), skipping ports already in use by
another mailbox in this DB and probe-binding each candidate so
external collisions are caught too. Cheap (microseconds per
probe on loopback) so we don’t bother caching engine-side.
Advisory only: the actual create_mailbox is authoritative and
will return PortInUse if the suggestion was beaten by a
racing create or by a process that grabbed the port between
the suggestion and the bind.
Sourcepub async fn start_mailbox(&self, id: &str) -> Result<()>
pub async fn start_mailbox(&self, id: &str) -> Result<()>
Bring a mailbox’s SMTP listener online and clear the persistent
paused intent. Idempotent — calling it on a running mailbox
returns Ok. Bind failures propagate so the UI can revert its
optimistic update and show the actual reason.
Sourcepub async fn stop_mailbox(&self, id: &str) -> Result<()>
pub async fn stop_mailbox(&self, id: &str) -> Result<()>
Tear down a mailbox’s SMTP listener and remember the user intent so the listener stays down across restarts. Idempotent.
pub async fn create_ephemeral( &self, input: CreateEphemeralInput, ) -> Result<EphemeralHandle>
pub async fn list_emails( &self, mailbox_id: &str, limit: u32, offset: u32, ) -> Result<Vec<EmailSummary>>
pub async fn get_email(&self, id: &str) -> Result<EmailDetail>
pub async fn get_email_raw(&self, id: &str) -> Result<Vec<u8>>
Sourcepub async fn get_email_smtp_transcript(
&self,
id: &str,
) -> Result<Option<String>>
pub async fn get_email_smtp_transcript( &self, id: &str, ) -> Result<Option<String>>
Load the SMTP transcript captured at ingest time, if present.
Returns Ok(None) when the email exists but the transcript pref
was off when it was received (the common case for older mail).
pub async fn delete_email(&self, id: &str) -> Result<()>
Sourcepub async fn clear_mailbox(&self, mailbox_id: &str) -> Result<u64>
pub async fn clear_mailbox(&self, mailbox_id: &str) -> Result<u64>
Clear all non-pinned emails from a mailbox. Pinned emails (set
via Self::set_pinned) survive. Use
Self::purge_mailbox to wipe everything including pinned.
Sourcepub async fn purge_mailbox(&self, mailbox_id: &str) -> Result<u64>
pub async fn purge_mailbox(&self, mailbox_id: &str) -> Result<u64>
Wipe every email in a mailbox — pinned ones included. Use only for explicit “purge” actions (rare).
pub async fn set_pinned(&self, id: &str, pinned: bool) -> Result<()>
pub async fn set_starred(&self, id: &str, starred: bool) -> Result<()>
pub async fn set_note(&self, id: &str, note: Option<&str>) -> Result<()>
Sourcepub async fn set_tag(&self, id: &str, tag: Option<&str>) -> Result<()>
pub async fn set_tag(&self, id: &str, tag: Option<&str>) -> Result<()>
Set or clear the tag on an email. Plus-addressing
(user+tag@host) sets this automatically at ingest; this
method lets users override or clear it manually.
Sourcepub async fn release_email(
&self,
id: &str,
to: &str,
relay: &RelayConfig,
) -> Result<()>
pub async fn release_email( &self, id: &str, to: &str, relay: &RelayConfig, ) -> Result<()>
Forward a captured email to a real address via an external SMTP
relay. The original raw bytes are sent unchanged; the envelope
MAIL FROM defaults to the captured sender and the envelope
recipient is the new to.
Audit-logged (PROD.md §9.3): this is the only public-Service method that produces outbound network traffic, so users need a clear trail of when releases happen.
pub async fn search_emails( &self, q: &str, mailbox_id: Option<&str>, limit: u32, ) -> Result<Vec<EmailSummary>>
pub async fn mark_read(&self, id: &str, read: bool) -> Result<()>
pub async fn get_attachment_blob( &self, attachment_id: &str, ) -> Result<(Vec<u8>, Option<String>, Option<String>)>
pub async fn get_chaos(&self, mailbox_id: &str) -> Result<ChaosConfig>
pub async fn set_chaos(&self, mailbox_id: &str, cfg: ChaosConfig) -> Result<()>
pub async fn list_bounce_rules( &self, mailbox_id: &str, ) -> Result<Vec<BounceRule>>
pub async fn upsert_bounce_rule(&self, rule: BounceRule) -> Result<BounceRule>
pub async fn delete_bounce_rule(&self, id: &str) -> Result<()>
pub async fn get_settings(&self) -> Result<BackendSettings>
pub async fn update_settings(&self, patch: SettingsPatch) -> Result<()>
Sourcepub async fn analyze_spam(&self, id: &str) -> Result<SpamReport>
pub async fn analyze_spam(&self, id: &str) -> Result<SpamReport>
Score a captured email’s spam-likelihood. Local heuristics only; no network.
Sourcepub async fn analyze_links(&self, id: &str) -> Result<LinkReport>
pub async fn analyze_links(&self, id: &str) -> Result<LinkReport>
Extract + classify every link in a captured email . Does not HEAD-check links.
Sourcepub async fn analyze_auth(&self, id: &str) -> Result<AuthReport>
pub async fn analyze_auth(&self, id: &str) -> Result<AuthReport>
Inspect SPF / DKIM / DMARC headers and predict pass/fail . Header inspection only.
Sourcepub async fn analyze_list_unsub(&self, id: &str) -> Result<UnsubReport>
pub async fn analyze_list_unsub(&self, id: &str) -> Result<UnsubReport>
Validate the List-Unsubscribe / List-Unsubscribe-Post
headers per RFC 2369 + RFC 8058.
Sourcepub async fn render_preview(
&self,
id: &str,
profile: Profile,
) -> Result<RenderedPreview>
pub async fn render_preview( &self, id: &str, profile: Profile, ) -> Result<RenderedPreview>
Render the email’s HTML body through a client profile . Returns the transformed HTML + a list of transforms that ran.
Sourcepub async fn lint_html(&self, id: &str) -> Result<LintReport>
pub async fn lint_html(&self, id: &str) -> Result<LintReport>
Lint the email’s HTML for known client incompatibilities.
Sourcepub async fn audit_a11y(&self, id: &str) -> Result<A11yReport>
pub async fn audit_a11y(&self, id: &str) -> Result<A11yReport>
Accessibility check on the email’s HTML.
Sourcepub async fn export_recording(
&self,
mailbox_id: &str,
label: Option<String>,
) -> Result<Recording>
pub async fn export_recording( &self, mailbox_id: &str, label: Option<String>, ) -> Result<Recording>
Snapshot every email in a mailbox into a portable
.postcrate recording. The result serializes to
JSON via serde; the caller is responsible for persisting it.
Sourcepub async fn replay_recording(
&self,
mailbox_id: &str,
recording: &Recording,
) -> Result<u64>
pub async fn replay_recording( &self, mailbox_id: &str, recording: &Recording, ) -> Result<u64>
Replay a recording’s messages straight into a mailbox by
pushing them through the ingest worker. SMTP listeners,
chaos, and bounce rules are bypassed — this is for fixture
restoration, not for re-running a scenario.
Use Self::replay_email for a single SMTP-driven re-send.
Sourcepub async fn replay_email(
&self,
id: &str,
target_mailbox_id: &str,
) -> Result<()>
pub async fn replay_email( &self, id: &str, target_mailbox_id: &str, ) -> Result<()>
Re-inject one captured email’s raw bytes into a (possibly different) mailbox via the local SMTP listener — exercises chaos + bounce rules + parsing the way a real send would.
Sourcepub async fn wait_for_email(
&self,
predicate: EmailPredicate,
timeout: Duration,
) -> Result<WaitOutcome>
pub async fn wait_for_email( &self, predicate: EmailPredicate, timeout: Duration, ) -> Result<WaitOutcome>
Block up to timeout for an email that satisfies predicate.
Sequence:
- Subscribe to the event stream first (so we don’t miss an email that arrives between scan + subscribe).
- Do a one-shot scan of recent emails in case it already arrived before the call.
- Otherwise consume the broadcast until timeout.
The returned crate::matcher::WaitOutcome always carries the
list of emails seen during the wait, so callers can distinguish
“no email at all” from “email arrived but didn’t match”.
Sourcepub async fn assert_email_matches(
&self,
id: &str,
predicate: &EmailPredicate,
) -> Result<MatchResult>
pub async fn assert_email_matches( &self, id: &str, predicate: &EmailPredicate, ) -> Result<MatchResult>
Check a specific email against a predicate. The full
crate::matcher::MatchResult is returned (including any
mismatches) so callers can produce a structured diff.
pub async fn list_webhooks(&self) -> Result<Vec<Webhook>>
pub async fn create_webhook(&self, input: CreateWebhook) -> Result<Webhook>
pub async fn delete_webhook(&self, id: &str) -> Result<()>
pub async fn list_forwarding_rules(&self) -> Result<Vec<ForwardingRule>>
pub async fn create_forwarding_rule( &self, input: CreateForwardingRule, ) -> Result<ForwardingRule>
pub async fn delete_forwarding_rule(&self, id: &str) -> Result<()>
pub async fn list_audit( &self, limit: u32, offset: u32, ) -> Result<Vec<AuditEntry>>
pub async fn clear_audit(&self, older_than_days: Option<u32>) -> Result<u64>
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Service
impl !RefUnwindSafe for Service
impl Send for Service
impl Sync for Service
impl Unpin for Service
impl UnsafeUnpin for Service
impl !UnwindSafe for Service
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more