Protocol
Message, presence and IQ: the three stanzas
Everything an XMPP client does is built from three XML elements. Knowing which one carries what explains most of the rest.
An XMPP session is two XML streams, one in each direction, kept open for its whole length. Down them travel stanzas: the basic unit of meaning in the protocol, a first-level element named message, presence or iq in the jabber:client or jabber:server namespace. Stream features and the TLS and SASL elements are not stanzas.
Stanzas wait their turn. Negotiation comes first, in the order the layers impose: TCP, then TLS, then SASL, then XMPP, with resource binding offered only after authentication. Once that is done, either party can send an unbounded number of them.
Three primitives, one vocabulary
Each kind has its own job. Message is a push mechanism, the nearest thing the protocol has to email: address it, and the server SHOULD attempt to route or deliver it. Presence is a publish-subscribe mechanism built around a single subject, network availability, which the server fans out to subscribers. IQ, short for Info/Query, is a request-response mechanism akin in some ways to HTTP, one structured question paired with one structured answer. Children in any namespace ride inside all three, which is how chat, file transfer and group rooms fit into three element names; for IQ, the namespace of its single child element defines the exchange.
Why does presence travel with no to address?
Addressing is where the kinds first diverge. A message names its recipient in a to attribute and the server routes it there; only a message bound for the bare JID of the sender’s own account may omit it. Presence expects the opposite. A client SHOULD publish it with no to attribute, and the server then broadcasts the stanza to every subscribed entity; add a to, and it becomes a single delivery instead. A stanza a client sends for the server to process itself, roster work or a presence broadcast, MUST NOT carry one. Servers, add-on services and any other XMPP entity may publish presence, and who receives the broadcasts is settled by the subscription dance.
Five attributes, and who may write them
All three kinds share five attributes: to, from, id, type and xml:lang. The from is the server’s to give. On a stanza from a connected client, the server MUST stamp the full JID it assigned to that resource, or the bare JID for subscription-related presence, the two forms a JID takes. A stanza that reaches a client with no from at all is from the user’s own account. Type takes different values for each kind, error being the only one all three share; the message and presence values live in the instant messaging companion, RFC 6121. The fifth attribute exists because, as the specification puts it, “internationalization is for humans”: text meant for a person SHOULD declare its language, a child element may override it, and a server MUST NOT alter it. Section 8 of the core specification sets out all five, in an example that has Romeo marking a dnd status, “Wooing Juliet”, then repeating the line in Czech.
Can a stanza lie about its origin?
Not past its own server. On server-to-server streams both addresses are policed: the domainpart of a from MUST match the sending server’s validated hostname, agreed during SASL negotiation or Server Dialback, or the stream is closed with an invalid-from error, a stanza with no to at all meets improper-addressing, and a to aimed at the wrong host meets host-unknown or host-gone. The point, the specification says, is to help prevent certain denial-of-service attacks. A quieter rule guards the stream itself: a server MUST NOT process a partial stanza, and MUST NOT attach meaning to the timing of any part before the closing tag arrives. A stanza means nothing until it is whole.
IQ, the ledger that must balance
IQ is the strict kind, because it alone promises an answer. Its type attribute is REQUIRED and takes one of four values: get asks for information, set provides it, result confirms, error refuses. Anything else comes back as bad-request. Every get or set MUST be met with a result or an error, and an answer MUST never be answered, though the requester may send a fresh request. The payload rules are just as tight: a get or set carries exactly one child element, a result zero or one, and an error MAY echo the original child but MUST carry an error element. The id, merely recommended on the other two kinds, is what the requester matches the reply against.
What an error hands back
Stanza errors are recoverable, which is the difference from stream errors: the stream and the connection underneath it stay up. The error stanza keeps the kind of what triggered it, sets its type to error, typically swaps the from and to addresses, mirrors the id, and carries an error child naming the condition. Its type then tells the sender what to do: auth, retry with credentials; cancel, the error cannot be remedied; continue, only a warning; modify, change the data and resend; wait, temporary. The familiar cancel case is conflict, returned when a client tries to bind a resource name already in use.
Reading a session with the book open
Section 4 of the same RFC draws a session as a two-column diagram: the initial stream on one side, the response stream on the other, stream headers at the top, closing tags at the bottom, stanzas filed in between.
Sketch that diagram once by hand, then hold any connection trace against it. Strip away the negotiation traffic and count what sits at depth one: every element is a message, a presence or an iq, wearing the same five attributes whatever the software builds on them. When one of them misbehaves, look its condition up in the specification before suspecting the client; the document usually got there first.
rfc-editor.org is the site behind the link above; its page for RFC 6120 holds the full text of the core specification. Section 4 carries the stream definitions and the session diagram, section 8 the five common attributes and the three stanza semantics, section 8.3.3 the named error conditions, from bad-request onward.