Knowledge base

Connect a sending platform

entries in this scenario: 107
always-allow-relayingGlobalcriticalset by the HubDirectiveThe very reason a node sends mail at all — and the thing that makes it an open relay if granted to the wrong source.default-virtual-mta<source>criticalset by the HubDirectiveApplies when the stream has not been chosen by anything higher up — a header, a rule or a merge variable.process-x-virtual-mta<source>criticalset by the HubDirectiveA permission for the source — with it the header selects the stream and is stripped before delivery; without it the header does nothing and travels to the recipient.smtp-listenerGlobalcriticalset by the HubDirectiveIf no listener is declared, the node silently brings one up on 0.0.0.0:25.smtp-service<source>criticalset by the HubDirectiveTurning it off closes submission for the source without touching the others.api-key<transmissions-api>DirectiveThe line declares a key the application passes in the Authorization header; the directive is repeated to create several keys.invalid-virtual-mta-fallbackGlobalDirectiveInstead of a refusal, the message leaves through the stream named here; it works only at submission and only if the refusal is turned off in the source.jobid-prefix<source>DirectiveThe value is prepended to the tag that arrived in the header; a reserved value substitutes the login of the submitting user.process-x-job<source>set by the HubDirectiveA permission for the source: with it the header value becomes the message’s job tag, which is then used for selecting in the queue and for stopping a single mailing.reject-invalid-virtual-mta<source>DirectiveThe default is to reject; this same default quietly cancels the fallback stream until it is turned off here.reserved-smtp-in<source-group>DirectiveReserves the named number of slots from the node’s overall limit for the group: others will not take them, even when the node is loaded.source<smtp-user>set by the HubDirectiveBinds the login to a named source block; its settings apply after login and override what the connection’s address would have given.source<smtp-listener>DirectiveBinds the listener to a named source block, canceling the usual address-based matching for its connections.tls-certificate<smtp-listener>DirectiveThe certificate and key password for connections to this particular address and port; inherited from the node certificate.use-inbound-proxy<smtp-listener>DirectiveRequires a PROXY header at the start of the connection and takes the real client address from it; off by default.accept-invalid-recipients<source>DirectiveSyntactically invalid addresses are accepted and immediately bounced instead of being rejected right in the submission session; they will not be delivered either way.add-date-header<source>DirectiveAdds a date to a message when the submitting side did not set one; the third value also rewrites an existing one.add-message-id-header<source>set by the HubDirectiveAdds an identifier to a message when the submitting side did not set one; an existing one is not rewritten.add-received-header<source>set by the HubDirectiveThe normal behavior of a mail server is to leave a mark in the transfer chain; it is turned off so that the recipient does not see where the message was submitted from.allow-mailmerge<source>DirectiveOpens merge commands to the submitting side, with which one message is sent to many recipients with value substitution.allow-smtputf8<source>DirectiveAdvertises the SMTPUTF8 extension, allowing addresses beyond Latin script; sending is not guaranteed — the receiver may not support it.always-allow-api-submission<source>DirectiveOne line instead of listing the permissions required by submission through the vendor API; currently equivalent to the merge permission.await-slot<smtp-listener>DirectiveDecides for one listener whether to wait for a free slot or respond with a refusal; the node-wide line sets the same for all the others.command<domain>DirectiveMandatory for a pipe queue; substitutions with message properties are expanded in the line.disconnect-on-transient-error<source>DirectiveInstead of a 4xx response the engine drops the connection — for a submitting side that cannot handle temporary refusals.file-destination<domain>DirectiveA path with substitutions: the date, domain and recipient can be inserted right into the name.file-format<domain>DirectiveA file per message, a file per message with envelope addresses, or a shared mbox mailbox.header<pattern-list>DirectiveThe only rule with a parameter — first the header name, then the pattern; the entire header content is matched, including spaces and line breaks.http-delivery-url<domain>DirectiveMandatory for an http-delivery queue; an absolute address without credentials or a query string.immediate-tls<smtp-listener>DirectiveInstead of STARTTLS the node starts encryption as soon as the connection is accepted; this is a separate submission method, usually on port 465.inbound-proxy-timeout<smtp-listener>DirectiveThe limit for waiting for the PROXY header at the start of a connection; the default is five seconds, and zero means “wait forever.”jobid-header<source>DirectiveNames another message header from which the job label is taken; the usual method and the merge variable take precedence.mail-from<pattern-list>set by the HubDirectiveMatches the address from SMTP MAIL FROM — where bounces are returned — not the From address the recipient sees.max-message-size<transmissions-api>DirectiveA limit on the payload size of a request to the submission API; the size multiplier is mandatory, and the engine will not accept a value above two gigabytes.max-rcpt-per-message<source>DirectiveA ceiling on acceptance: how many addresses the node agrees to take in one message from the submitting system.max-smtp-in<source-group>DirectiveLimits how many connections a group of sources can hold to the node at once; the default limits nothing.pickupGlobalDirectiveSets a pair of paths: where to read submitted files from and where to put the ones that could not be processed. Only one directory is supported.process-x-schedule<source>DirectiveA permission for the source: with it the engine delivers a message only within the intervals named in the header; without it the message is delivered in the usual way.rcpt-to<pattern-list>DirectiveMatches the address from SMTP RCPT TO; with several recipients the stream of the first match applies to the whole message.relay-debugGlobalDirectiveSwitches relay control into debug mode: instead of a final refusal the node responds with a temporary one, and the message stays with the sender instead of bouncing.smtp-await-slotGlobalDirectiveWhen there are no free inbound connection slots, the node either waits for one to free up or answers with a 421 greeting and closes the connection.source-group<source>DirectiveNames the group the source is assigned to; the limits shared by the group are set in the group block, not here.suppress-local-dsn<source>set by the HubDirectiveTurns off bounce, delay and delivery report messages for submission from this source; accounting records are written as usual.tls-min-version<smtp-listener>DirectiveThe oldest protocol version accepted on this address and port; the default is TLS 1.2, as for the node.too-many-rcpts-fails-message<source>DirectiveInstead of refusing the extra recipients, the engine rejects the message at the DATA command; it works together with the recipient number limit.total-max-smtp-inGlobalset by the HubDirectiveLimits the number of simultaneous inbound SMTP connections for the whole node.allow-chunking<source>DirectiveAllows the submitting side to transfer a message with the BDAT command instead of DATA; the default is to allow.allow-empty-x-virtual-mta<source>DirectiveWith this line a message with an empty header is accepted and leaves via the default stream; without it this is an invalid stream and a rejection.auto-qualify-domain<source>set by the HubDirectiveAn address of the form user@host arriving in MAIL FROM or RCPT TO is completed to a full one by adding a suffix; the default is to complete.date-header-time<source>DirectiveChooses between the time the message was received and the time of actual delivery; applies only where the node adds the date itself.domain-suffixGlobalDirectiveThe suffix appended to a single-part domain when completing addresses; it works only together with completion itself.http-delivery-extra-headers<domain>DirectiveThe only place to put authorization: credentials in the address itself are forbidden.log-data<transmissions-api>DirectiveMore detailed logging than the submission API request log; off by default.log-inbound-proxy<smtp-listener>DirectiveWrites the received PROXY header to the log; works only with reception of such a header enabled.log-requests<transmissions-api>DirectiveWrites to the log the fact of every Transmissions API request; off by default.log-tls<source>DirectiveDetails of encryption negotiation with the submitting client, in the node log; the default is not to record.log-tls<transmissions-api>DirectiveThe switch for detailed logging of encryption negotiation when handling HTTP API requests; off by default.macro-variables-preserve-case<domain>DirectiveApplies only to $to and $from: the recipient’s user name and domain are always lowercased.mailmerge-expands-undefined-variablesGlobalDirectiveWith the default an undefined variable turns into nothing; with the value false it stays in the message as is, brackets included.process-x-envid<source>DirectiveA permission for the source: with it the header value becomes the message’s envelope identifier and the header is removed; without it the header is ignored and stays in the message.replace-message-id-header<source>DirectiveRewrites an existing Message-Id with its own; has no effect at all on a message without an identifier.retain-x-dkim-options<source>DirectiveDecides whether the recipient will see the header with signing settings; the default is to remove it.retain-x-job<source>DirectiveDecides whether the recipient will see the job label; works only when reading the header is allowed and the header is present in the message.retain-x-schedule<source>DirectiveDecides whether the recipient will see the sending windows assigned to the message; the default is to remove it.retain-x-virtual-mta<source>DirectiveThe default is to remove it; a header left in place carries internal stream names to the recipient.smtp-command-timeout<source>DirectiveThe wait limit for data from the submitting side during the command exchange; the paired line to the body transfer limit.smtp-data-timeout<source>DirectiveThe wait limit for data from the submitting side after the DATA or BDAT command; applies only to incoming connections.tls-ca-file<smtp-listener>DirectiveA list of root certificates for verifying clients on this input; the manual does not promise inheritance from the node’s list.tls-cipher-server-preference<smtp-listener>DirectiveWith this line the cipher is chosen by our order, not by the client’s order; the default is by the client.tls-ciphers<smtp-listener>DirectiveThe list of allowed ciphers in OpenSSL notation for connections on this input; applies up to and including TLS 1.2.tls-max-version<smtp-listener>DirectiveThe newest protocol version accepted on this address and port; unlimited by default.tls-v1.3-ciphersuites<smtp-listener>DirectiveA separate list for version 1.3 on this input; the default lists five modern suites.total-max-transmissions-apiGlobalDirectiveHow many submitting HTTP connections the node serves at once; the engine does not check an upper bound — the operating system sets it.pickup-remove-dotGlobalDirectiveA concession to programs that escape a dot by SMTP rules where it is not required — in pickup directory files.Who is allowed to submit mail and for whom to accept itcriticalMechanismOut of the box, the node accepts submission only from the machine itself; two different questions — “who can send through us” and “for whose addresses we accept mail” — are answered by different directives.Headers the sender uses to control deliverycriticalMechanismSix control headers let the submitting side choose a stream, tag a message with a job, set signing options and the key, the envelope identifier and the schedule; each is allowed separately and per source.What the submission bindings needMechanismWhat must be in place on the submitting side for the bindings to work: a library, permissions and group membership.What the submitting system assembles before sendingMechanismAll five language bindings provide the same three objects — a connection to the node, a message and its recipients — assembled in a fixed order.The source default is the bottom rung, tied to whoever connectsMechanismA source block matching the sender’s address can name a default stream; it applies when no choice was made higher up the ladder.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.Personalization inside the engineMechanismVariables are set per recipient, and the node substitutes them at delivery — one submitted message goes to many recipients with different content.Node metrics in a standard formatMechanismThe node exposes counters, gauges and summaries in a widely accepted format: traffic, connections, errors, queue depth and delays.Submission is a network service, and you can log into itMechanismThe submitting application connects to the node by name or address and port — either without login or with a name and password the node is configured to accept.Selecting a sending address by message contentMechanismRegular expressions are matched against a header, the return address or the recipient and select a sending address or assign a priority; lists can call each other.How a binding reports an errorMechanismThe C++ binding reports an error with an exception, after which the object is discarded; the C binding with a returned flag and a separate query for the last error.The HTTP submission formatMechanismInstead of a finished message, an HTTP request can carry the sender, subject, headers, text, HTML, AMP and attachments as separate fields — the node assembles and encodes the message itself.The line ending requirementMechanismLines of a submitted message end with a CRLF pair; a lone LF is the most common error of a home-grown submitting program, and it is diagnosed with a session recording.Mail merge via SMTP extensionsMechanismMail merge over SMTP: XMRG instead of MAIL FROM, XDFN with variables before each recipient, and XPRT instead of DATA for each part.Authentication during deliveryMechanismThe node logs in on the receiver’s side with the login and password from the <domain> block — CRAM-MD5, LOGIN or PLAIN, if the receiver supports them.Submitting a message by writing a file into a directoryMechanismThe message is placed as a file in a directory, and the envelope is passed in special headers at its start; the engine takes the file into the spool and delivers it.Five ways for a queue to hand off a messageMechanismA queue does not have to use SMTP: it can write to a file, run a program, call over HTTP or discard.The stream follows the address you connected toMechanismA named source block is attached to a listener and applies to everyone who connected to that address and port — so the sender picks the stream by picking the connection point.Encodings at submissionMechanismMessage data in a binding is added as 7-bit, 8-bit or base64: the first two do not change the data except for converting a lone LF to CRLF, base64 encodes on the fly; merge data supports only 7-bit and 8-bit.How a message gets into the engineMechanismSix described submission methods: extended SMTP, four language bindings and a directory the node watches on disk.Submission over HTTPS on its own listener, modeled on SparkPostMechanismA separate entry point: its own listener with a certificate, its own keys and a reserved source name through which the usual submission settings apply to such mail.The load balancer header at the entranceMechanismThe node reads the PROXY header at the start of an incoming connection and treats the address from it as the source; this works for both kinds of entry point.National alphabetsMechanismConfiguration files are UTF-8, so internationalized domains and addresses are written as is; a message with an internationalized address in the envelope goes out only if the receiver supports SMTPUTF8.C submission APIMechanismThe C binding: the same operations as functions with the PmtaConn, PmtaMsg and PmtaRcpt prefixes, with explicit allocation and freeing of objects and a query for the last error.C++ submission APIMechanismThe C++ binding: connection, message and recipient classes in three header files; an error throws an exception and makes the object unusable.Java submission APIMechanismThe Java binding: pmta.jar in the classpath and a provider file for JavaMail; the description is in JavaDoc.Initial configurationcriticalProcedureThe manual requires two things to be set by hand: the responsible person’s address and relaying control — sources for submitting machines with always-allow-relaying; reception rules are needed only if the node accepts inbound mail.Troubleshooting mail receptionProcedureThe troubleshooting procedure when messages are not accepted: enable connection and command logging for the source, look at the session, turn it back off.<source>criticalConfiguration blockRules for whoever connects to submit: whether relaying is allowed, which control headers to honor, which limits apply and whether authentication is required.<smtp-listener>Configuration blockSettings that apply to connections on one address and port: encryption, rights through a named source, behavior when the ceiling is reached.Submitting a message over HTTPAPI endpointAccepts a message as a JSON request over HTTPS instead of an SMTP session — with recipients, substitutions and content.ReceivedAccounting recordThe message was successfully submitted to the node — through a mail session or through the submission interface.Latency on receptionMetricThe number of submissions and the time by reception stage.