loopback

package
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package loopback delivers agent-to-self messages without touching the upstream SMTP relay. A self-send (agent emails itself) is a degenerate case for SMTP: the relay would refuse it as a self-spam guard, and the roundtrip through SES + MX + the local SMTP receiver is wasted work when the destination is local anyway.

The package owns self-recipient detection and byte-identical MIME composition. Persistence lives in the identity store so Sent/Inbox rows, idempotency, and outcome events can share one database transaction.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ComposeMIME

func ComposeMIME(agent *identity.AgentIdentity, req outbound.SendRequest, providerID, fromDomain string) ([]byte, error)

ComposeMIME builds the RFC 5322 / 2046 message bytes the inbound row will store as raw_message.

Delegates to the same composer the real SMTP path uses (outbound.ComposeMessageWithAttachments) so the produced message is byte-equivalent to what an external roundtrip would have generated — same headers, same multipart structure, same attachment encoding. The SDK's InboundEmail.fromPayload → parseRawEmail pipeline then finds body text/html AND attachments without any loopback-specific branch.

Prepends ONE synthetic Received: line per RFC 5321 §4.4 ("each time a message is relayed... the receiving SMTP server MUST insert a 'Received:' line"). Mature local-delivery MTAs (sendmail's local mailer, Postfix's local daemon, Exim's local_smtp transport) all add such a line even for same-host delivery; doing the same here keeps stored messages forensically self-documenting. The "loopback" keyword is the searchable signal — `grep "with loopback"` over raw messages finds every self-send.

Threading: req.ReplyToMessageID and req.References are passed through to the composer, so self-replies that reach this path via the HITL approval finalizer preserve In-Reply-To / References headers — same shape an SMTP-routed reply would carry.

func IsSelfSend

func IsSelfSend(req outbound.SendRequest, agentEmail string) bool

IsSelfSend reports whether req targets only the sender's own inbox — i.e., the agent is writing a note to itself. Returns true only when there's a single To recipient that matches the agent's own address (case-insensitive, trimmed) AND no Cc/Bcc — any mixed/external recipient routes through normal SMTP unchanged.

Callers that have CC/BCC carrying agent aliases (e.g. the reply path with replyAll=true on a self-thread, where the original message's CC list already includes the agent) should strip them via StripAgentSelfAliases before checking — outbound.Sender does the same alias-strip downstream as a self-spam guard, so doing it here is purely "see through" the aliases earlier.

func ProviderID

func ProviderID(fromDomain string) string

ProviderID synthesizes an RFC 5322-shaped Message-ID for the outbound row's provider_message_id column. Mirrors what an external MTA would have stamped — keeps the column non-empty and recognizable in operator queries (the "@loopback.<domain>" host portion makes self-sends greppable across the dataset).

func StripAgentSelfAliases

func StripAgentSelfAliases(addrs []string, agentEmail string) []string

StripAgentSelfAliases removes case-insensitive, whitespace-trimmed matches of agentEmail from addrs. Used to pre-clean reply recipients so IsSelfSend can recognize replyAll-on-a-self-thread as still a self-send. Returns a fresh slice; the input is not mutated.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL