Are Emojis Allowed in XMPP Addresses?

ge0rg1 pts0 comments

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...

precis xmpp unicode valid address characters

Related Articles