Knowledge base

Troubleshoot deliverability

entries in this scenario: 86
disable-acct-records<domain>criticalDirectiveDisables the creation of accounting records of the chosen types — delivery, bounce, transient failure, queuing failure — for an individual queue.record-fields<acct-file>criticalset by the HubDirectiveThe field list for one record type; the default is the star, meaning the default field set marked in the manual’s tables; it supports exclusions and arbitrary message headers.retry-after<domain>criticalset by the HubDirectiveIt can be set as a sequence: 10m, 1h, 4h — and then the pauses grow from attempt to attempt.smtp-proxy-source-hostGlobalcriticalDirectiveThe vendor’s way to send through a proxy — local address, proxy, client address and greeting name in one line.auto-mx-rollupGlobalDirectiveOne line instead of a list: the node groups the domains itself and makes up the queue name itself.backoff-notify<domain>set by the HubDirectiveA message arrives for both events — entering backoff mode and leaving it.backoff-retry-after<domain>set by the HubDirectiveThe retry schedule for the duration of backoff; set as a sequence.bounce-category-patterns<domain>DirectivePuts your own reply parsing ahead of the general one — without changing whether the message bounced.check-spf-outbound<domain>DirectiveIf it fails, the message is bounced on our side before it reaches the receiving server; a temporary error means a retry.discard-as-bounce<domain>DirectiveA discard queue still writes to accounting — this line decides with which letter.name-serverGlobalDirectiveSets name server addresses; the line is repeated, and the engine goes through them in rotation. If not set, the operating system’s resolvers are used.precached-domains-file<dns>DirectiveA text file with one domain per line; the listed domains are resolved regardless of whether there are messages for them in the queue.precached-refresh-interval<dns>DirectiveSets a refresh schedule instead of the receiver’s record time to live: these domains’ own TTL is ignored.proxy-retry-after<domain>DirectiveThe same retry step, but for the case when the connection through the proxy did not reach the receiver.retry-recipients-after<domain>set by the HubDirectiveA lower bound on the pause for an address that got a 4xx response — on top of the queue’s common schedule.smtp-553-means-invalid-mailbox<domain>set by the HubDirectiveA guess in place of what the receiver left unsaid — and whether the address ends up on the blocklist depends on it.track-time-first-attemptGlobalset by the HubDirectiveEnables tracking the time of the first attempt; it opens a field in accounting records and a delay metric. Off by default.use-dane<domain>DirectiveThe node reads the recipient domain’s DANE records, requires encryption if the domain requires it, and checks the certificate against the fingerprint from DNS; the default is off.allow-cancel-during-transfer<domain>DirectiveThe default allows it — for a fast service shutdown; turning it off protects against duplicates but makes the node stop more slowly.auth-password<domain>DirectiveThe second half of the pair; the hash sign is not allowed in it — the engine treats it as the start of a comment.auth-username<domain>DirectiveOne of the two lines that enable outgoing authentication: either of them being non-empty is enough.connect-timeout<domain>DirectiveThe first timeout of the conversation: things have not yet reached the greeting.edns-udp-lengthGlobalDirectiveEnables the EDNS extension and sets the maximum UDP response size; without it responses longer than 512 bytes are truncated, and the route may be assembled incompletely.log-commands<source>set by the HubDirectiveWrites the full exchange of commands and responses to the log; the vendor calls this the first step when investigating connectivity.log-disabled-ips<domain>DirectiveThe only source of history: the list of disabled addresses shows “now,” the log shows “what happened.”max-events-recorded<domain>DirectiveNot a log but memory: the last ten errors for a domain, visible in the console and the web monitor.max-msg-per-connection<domain>set by the HubDirectiveThe default is zero, no limit: it pays for the engine to send as much as possible over one connection.max-rcpt-per-transaction<domain>DirectiveCuts a message with a large list into several transfers: more parallelism, but the body goes to the receiver as many times as there are pieces.precached-max-domains<dns>DirectiveA ceiling on the number of domains taken from the file; it cannot exceed the number of lines in the file, and extra lines are cut off silently.retry-after-dns-error<domain>set by the HubDirectiveA separate, shorter step: the receiver never saw this attempt, and haste does not threaten it in any way.smtp-421-means-mx-unavailable<domain>set by the HubDirectiveThe vendor default is to stay on the same connection; enabling it moves the queue to the receiver’s backup server.smtp-data-termination-timeout<domain>DirectiveThe last wait of the conversation — and the most dangerous one: shorten it and you get duplicates.time-first-attempt-domains-file<prometheus-listener>DirectiveA list of receivers, up to a hundred names, for which the first attempt metric gets its own label; the rest fall into other.track-outbound-perf-statsGlobalDirectiveEnables counting the time from MAIL FROM to the end of DATA when sending; useful only together with the metrics listener.track-recipient-events<domain>DirectiveOff by default: the queue page says nothing about what happened to specific addresses.use-unencrypted-plain-auth<domain>DirectiveBoth mechanisms transmit the password in the conversation; without encryption it goes over the network in the clear.data-send-timeout<domain>DirectiveThe third wait of the conversation; the manual reminds: less than three minutes violates the mail standard.ignore-8bitmime<domain>DirectiveA workaround for a known incompatibility: the external gateway accepts 8BITMIME, while the internal one behind it does not.ignore-chunking<domain>DirectiveA debugging switch: returns the transfer to the ordinary DATA command.ignore-dsn<domain>DirectiveCancels the delivery report requests the message carries from submission.ignore-pipelining<domain>DirectiveThe second debugging switch: commands go one at a time, with a reply to each.log-resolution<domain>DirectiveWrites to the log the course of name and route lookup for the receiver; off by default.log-transfer-failures<domain>set by the HubDirectiveWrites a warning when the connection breaks while headers and body are being transferred; off by default.max-rcpt-per-message<domain>DirectiveThe same splitting limit under another name — and a full namesake of the reception setting from the submission block.replace-smtp-421-service-response<domain>DirectiveReplaces the text after the 421 code with “service unavailable”, so that addresses from someone else’s reply do not get into the bounce report; pattern-based parsing keeps working.smtp-greeting-timeout<domain>DirectiveThe second wait of the conversation: there is a connection, the receiver is silent.The telemetry contractcriticalMechanismOne block describes the accounting output in full: which record types, which fields, where they go, how files rotate and what gets anonymized.How the policy for a receiver is assembledcriticalMechanismSettings are assembled from the most general pattern to the most precise; the order of blocks in the file means nothing.How the node responds to the receiving server's wordscriticalMechanismMatches SMTP replies against regular expressions and changes the queue mode on a match — the very trigger that all of the backoff mode machinery waits for.How an accounting record is structuredcriticalMechanismHow an accounting record is structured: the record type in the first column, then the fields, whose composition is configurable.Backoff mode — the queue's second personalitycriticalMechanismA queue that a receiver has started refusing switches to a parallel set of limits, retries and routes — ten directives that act only in this mode.Complaints parsed by the node — and they are parsed secondcriticalMechanismMail that arrives at an address from the configured list is parsed as a complaint report; the parsing order matters — the complaint processor runs after the bounce processor.What the node tells about itself and through which channelscriticalMechanismSeven observation surfaces: the web monitor, the console in four formats, the log, accounting, accounting search, metrics and export to external analytics.Do not send what will fail the check at the receivercriticalMechanismThe node checks the SPF of its own mail before sending: if it fails, it bounces the message without waiting for someone else’s refusal.Recipient eventscriticalMechanismThe last 50 delivery, bounce and deferral events per queue — enabled with track-recipient-events and visible in queue output.Reputation monitoring inside the nodecriticalMechanismThe engine itself watches the receiving servers’ replies and changes the queue mode on a pattern match — a reaction within the connection, not through telemetry.Seeding campaigns with control addressesMechanismThe engine mixes the vendor’s addresses into a mailing, and the result is viewed in the vendor’s deliverability tool; independent of event export.Markup parsing and editingMechanismOpen and click tracking in sparkpost mode edits the message markup with the built-in gumbo-parser; by default a message whose markup could not be parsed is bounced.Exposing metrics to a collectorMechanismExposing the node’s metrics to an external collector in its format.The watchdog that restarts the engineMechanismKeeps an eye on the engine and brings it back up after a crash by itself, sending a crash report to the postmaster address.The directive indexMechanismThe manual’s alphabetical index: 475 lines name 477 places where directives are documented — the only complete inventory of the configuration language.Third-party components of the engineMechanismPowerMTA runs on five third-party libraries — PCRE, OpenSSL, ICU, gumbo-parser and prometheus-cpp; their behavior is determined by the engine build.Figure out why a queue to one receiver is growingProcedureFirst check the route and reachability with one command, then make the node attempt delivery with the session logged, and only for an intermittent problem enable per-receiver logging.<dns>Configuration blockThe DNS precache block: a file with a list of domains, a ceiling on their number and a refresh schedule. Resolvers are set outside the block.disable sourcecriticalCommandThere is an option to bring it back automatically after an interval — without it the address stays disabled forever.show queuescriticalCommandShows the selected queues and, unless told otherwise, the last fifty deliveries, bounces and delays; selection is by connection, mode and pause state.show settingscriticalCommandPrints the settings for a “receiving server and sending address” pair after all blocks have been merged.resolveCommandQueries a domain’s MX records and addresses and with –connect connects to the first available mail host.show domainsCommandPrints recipient domains, summing up all sending addresses for each.traceCommandOpens a connection to a domain and tries to deliver one message from the queue, writing the SMTP conversation to the log.pmtastatsCommandComputes throughput and traffic statistics from accounting files — for the node, sending addresses, jobs and domains.acctfindCommandSearches accounting files for records by fields and prints the selected fields in one of seven formats.Details of one queuecriticalAPI endpointReturns one queue with short histories: the latest recipient events, errors and mode changes.Details of one receiverAPI endpointReturns the state of one recipient domain.Delivered — the record everything is counted bycriticalAccounting recordWritten for every recipient whose message the destination server accepted: the outcome, the time, the sending address, the job, transport security and the proxy.ComplaintAccounting recordA complaint report was received and parsed by the configured processor.Temporary failureAccounting recordOne delivery attempt failed, and the recipient stays in the queue until the next one.Delivery notificationAccounting recordA delivery status notification that is not a bounce has arrived — for example, a delivery confirmation.The receiver refused the connectionError codeThe connection was not established: the remote host rejected it — either the mail server is down, or a filter is rejecting this particular sender.Refusal at the greetingError codeThe receiver returned an error at the very first step of the conversation — usually 4xx: busy, temporarily not accepting mail or not allowing this connection.The receiver dropped the connectionError codeThe remote host unexpectedly closed the connection — the server was shut down or crashed, or this is how it responded to the message content.Three short histories for each queuecriticalMonitor screenThe page of a single queue carries the last fifty recipient events, the last ten queue errors and the last ten mode changes.Receivers summed across all sending addressesMonitor screenThe busiest recipient domains by number of recipients: volume, open connections and the last error, plus a form for selecting a specific domain.Spam trapsMonitor screenThe SparkPost Signals report on spam trap hits by day — as a count or as a share of the day’s volume.The vendor analytics overviewMonitor screenThe SparkPost Signals overview: leaderboards by health score and spam traps broken down by campaign, pool and sending domain, for up to 90 days.Service summaryMonitor screenThe SparkPost Signals report with sending metrics for a selected period, grouped by domains, campaign, address and pool.