Skip to content
Presence & ProtocolAn independent guide to Jabber and XMPP

Protocol

How a JID is built, and what breaks it

An XMPP address looks like an email address and is not one. The differences are written down, and they matter.

A green painted front door seen close up, with a brass letter slot, a bell push and a worn handle.

Every piece of XMPP traffic is addressed, and the address is a string of Unicode text, encoded as UTF-8 and cut, in order, into localpart, domainpart and resourcepart. For historical reasons, that address is called a JID. An at sign joins the first two parts, a slash joins the last two, and only the middle part is compulsory. Most of what breaks an address is a mishandled part or a misplaced separator.

The grammar fits on one line: [ localpart "@" ] domainpart [ "/" resourcepart ]. Square brackets mark what may be left out: a bare domain is already a complete address, and so is a domain with a resourcepart attached. The specification’s worked example is [email protected]/balcony, a person at her server, on one named connection. The small XML pieces that travel an XMPP stream, the three stanza types, each carry one of these strings as their destination.

Why can a domain stand alone?

Because it is the primary identifier. The domainpart is the only required element of a JID, and it usually names the home server a client connects to. It need not: a domainpart can name a chat service, a publish-subscribe service or a user directory. It must be a fully qualified domain name, an IPv4 address, an IPv6 address in square brackets, or a hostname that resolves on the local network. The last two carry warnings: other services may refuse IP literals for server-to-server traffic, and unqualified hostnames are invisible outside their own network. In practice that leaves domain names, and what a server publishes in DNS decides whether anyone can find it.

The localpart and its forbidden characters

The localpart is the optional piece before the at sign, and it usually names a local account. It can equally name a chatroom, which is why a room is addressed exactly like a person. Its rules come from the UsernameCaseMapped profile of PRECIS, a name that announces its habit: case is mapped away before comparison. Eight characters are excluded on top of the base rules: the quotation mark, the ampersand, the apostrophe, the solidus, the colon, the less-than and greater-than signs, and the at sign itself. Two of them are the address’s own separators. XEP-0106 defines an escaping scheme for stubborn cases.

What does the resourcepart actually name?

A connection, usually. The resourcepart is the optional piece after the slash, and it tells one device, location or connection apart from the others an account may hold open. The specification asks for humility here: treat resourceparts as opaque strings and read no meaning into them. The at sign is allowed inside a resourcepart, and chatroom services use it for handles, so [email protected]/user@host reads as an occupant of that room with the handle user@host. Services, the specification notes, do not necessarily check an asserted handle against the occupant’s real address. A handle that looks like a JID may not be one.

A slash is not a path

Unlike web addresses, an XMPP address is not hierarchical, and the address format document spells this out. The first slash ends the domainpart, and everything after it forms one opaque string: [email protected]/foo/bar does not describe a resource called bar below a resource called foo. The order of parsing is fixed: cut from the first slash to the end, then cut from the start to the first at sign. One implementation note deserves a slow read: the separators must be matched before any normalisation runs, because normalisation can decompose certain Unicode code points into an at sign or a slash. Split first, simplify second, or the address comes apart in the hand.

Counting octets, not characters

Each part may run from one to 1023 octets after normalisation, which caps a whole address, separators included, at 3071 octets. UTF-8 can spend up to four octets on a single character, so a resourcepart built from emoji or accented letters reaches its ceiling sooner than its character count suggests.

The three parts compared
PartCompulsoryLength in octetsRules applied
localpartno1 to 1023PRECIS UsernameCaseMapped
domainpartyes1 to 1023IDNA2008
resourcepartno1 to 1023PRECIS OpaqueString

When are two JIDs the same?

When their bytes match, after preparation and enforcement, a state the specification calls bit-string identity. A trailing dot on a domainpart is stripped first, before any other canonicalisation. ASCII encodings of internationalised labels are converted back to their Unicode form during preparation. Everything is encoded as UTF-8, and the two strings are compared octet for octet. Two addresses that look different to a reader but sit identical to a machine are separated by exactly these steps, and software that compares JIDs as plain strings will occasionally get the answer wrong.

Take your own address apart

The next time a client shows the full address it is using, parse it the way the specification does. Find the first slash and cut. Find the first at sign in what remains and cut again. Read the three pieces in order: the last one names the device or connection in use right now. Count its octets, not its characters, and you will know how much room it has left under the ceiling.

Where these rules are published

rfc-editor.org is where the RFC documents themselves are published, each at its own page. RFC 7622 defines the native format of a JID, and RFC 6120 sits alongside it as its complementary page. The text of RFC 7622 also points to the specifications it builds on, including RFC 7613 for the PRECIS profiles and RFC 5122 for the URI form of an address.