Are Emojis Allowed in XMPP Addresses?
Navigation
Homepage
Blog
Archive
github
🦣 chaos
📸 photo
Tags
android
boot
graphics
hardware
homebrew
misc
net
reverse-engineering
samsung-nx
xmpp
Blogroll
bunnie
debugmo.de
pagetable.com
xnyhps
yosefk
Georg Lukas, 2026-07-17 20:33
So I was bored and I set up an XMPP server under<br>👆️.op-co.de, in addition to the one I already had under<br>ツ.op-co.de. It worked with some clients and failed with<br>others. But both ツ and 👆️ are valid Unicode 1.1 characters, so WTF?<br>Buckle up (or better: put on your 🤿) for the 19-RFC deep dive...
...or skip right to the TL;DR.
Note: despite my generous use of Emojis throughout this post, none of it was<br>generated by a text extruder machine. All words are the product of<br>artisanal typing on my keyboard, and the Emojis were hand-selected from an<br>Emoji-picker widget.
XMPP addresses
PRECIS: Preparation, Enforcement, and Comparison of Internationalized Strings
PRECIS classes, profiles and categories
XMPP address elements
localpart - the user name
The domain part
The resource part (a.k.a. chatroom nickname)
Hysterical raisins
2004: The Original Specification
2008: A New IDNA Hope
2010 Revenge of the PRECIS
2015 The Next Generation
XMPP address validation in the wild
Consensus in distributed systems
Robot Face vs. the MUC Occupants
Looking at implementations
Server implementations
Client implementations
Implementation overview
Summary / TL;DR
XMPP addresses
XMPP, the eXtensible Messaging and Presence Protocol,<br>formerly known as Jabber®, defines its address format in<br>RFC 7622.
An XMPP address (formerly known as Jabber® ID, or JID, as used in the RFC) has three parts:
jid = [ localpart "@" ] domainpart [ "/" resourcepart ]
The localpart is usually the username, but is not used when addressing a server.
The domainpart is the hostname or domain name, and can be a Unicode DNS<br>identifier, an IPv6 address in square brackets, or a legacy IP address. This<br>is the only mandatory part of a JID.
The resourcepart is the internal identifier of an individual client,<br>allowing a user to have multiple clients connected at the same time; it is<br>also used for the nickname in<br>XEP-0045: Multi-User Chat.
Each of these three parts must be valid UTF-8 and can be up to 1023 bytes (not<br>characters!) in length.
Furthermore, there are restrictions for each part, for example:
localpart = 1*1023(userbyte)
a "userbyte" is a byte used to represent a UTF-8 encoded Unicode code point<br>that can be contained in a string that conforms to the UsernameCaseMapped<br>profile of the PRECIS IdentifierClass defined in RFC 7613<br>[...]
Come again, please? Okay, let's take this apart, slowly.
a "userbyte" is a byte used to represent a<br>UTF-8 encoded Unicode code point
This is a convoluted way to say that we accept up to 1023 bytes (not<br>characters!) of valid UTF-8.
that can be contained in a string that conforms to the UsernameCaseMapped<br>profile of the PRECIS IdentifierClass defined in RFC 7613
In addition to being valid UTF-8, it must also conform to the<br>IdentifierClass in PRECIS (RFC 7613).
PRECIS: Preparation, Enforcement, and Comparison of Internationalized Strings
PRECIS is the successor to Stringprep<br>(RFC 3454, which we can<br>ignore for now).
However, the PRECIS definition in RFC 7613 is obsoleted by RFC<br>8265, which we can't ignore and will have to take our character<br>profiles and classes from.
So we need the IdentifierClass for the localpart, and furthermore<br>the FreeformClass for the resourcepart.
PRECIS classes, profiles and categories
The earlier Stringprep approach explicitly defined its classes as valid ranges<br>of Unicode code points (characters). However, given that Unicode is a living<br>(versioned) standard, new characters (and new Emojis! 💡) get added every<br>year. This left Stringprep in an uncomfortable place, forever hard-coded to<br>the long-superseded 2002<br>Unicode 3.2 standard.
To allow for future compatibility, PRECIS took a different path. It<br>describes an algorithm that can be applied to an individual Unicode<br>character in order to determine whether it belongs to a certain PRECIS<br>class.
The classes (IdentifierClass and FreeformClass) are defined in<br>RFC 8264, and the profiles (UsernameCasePreserved,<br>UsernameCaseMapped, OpaqueString, Stringprep) are defined in<br>RFC 8265.
Furthermore, PRECIS attempts to retain backward compatibility with earlier<br>standards like IDNA2008, as well as with itself. If a certain character is<br>"valid" under an earlier version of Unicode, PRECIS tries to ensure that it<br>stays "valid" under later versions. The only explicit exception from this is<br>that code points that were "undefined" in earlier Unicode versions can later<br>be assigned and move to "valid" or "disallowed".
Each of these rules is applied to individual characters, or to character<br>categories, as defined in RFC 5892: IDNA code points.
Given this toolset, we can now get back to the individual XMPP address parts.
XMPP address elements
localpart...