XMPP is almost 20 years old now, and I've been using it while looking for ways to get distributed messaging. New protocols and technologies are fun, but XMPP has good documentation, works, can be used in either federated or distributed fashion (as most of the other federated systems, coupled with Tor or a similar network), and has plenty of software – so now I think that it is quite sufficient for messaging.

Its specifications (see RFC 6120, RFC 6121, RFC 7622, and extensions) are well-written and apparently thought through, a small core with optional extensions is a nice approach, there is usable software, there are users. Though the situation with software could have been better.

Desirable features

XEP-0423: XMPP Compliance Suites 2020 lists rather useful and important XEPs; I'd like to focus on some of those, and a few more here:

Message handling acknowledgements
XEP-0198, needed for reliable message delivery.
Message carbons
Some users tend to switch between resources (clients, connections, or devices) frequently, leading to a confusion caused by messages sent to a wrong resource altogether, and/or incomplete message history in some of the client instances. Message carbons (XEP-0280) help to solve that by delivering incoming and outgoing messages to all the connected resources.
Client authentication
SASL EXTERNAL authentication mechanism is needed for key-based authentication, which is not an essential feature, but nice and handy.
SCRAM is fine for password-based authentication, and required by the current standard, but not every client supports it.
Many implementations are not easily reusable from common languages, so that's another aspect I'm paying attention to. Ideally, there should be a C API and a sensible way to hook it up to an external event loop.
End-to-end encryption
OpenPGP (obsolete XEP-0027, deferred XEP-0374), which is commonly used for other purposes, has nice software such as gpg-agent, supported by smart cards, etc. Though it doesn't provide forward secrecy, has a relatively high overhead, and generally not that fancy.
OTR (deferred XEP-0364), which is generic, IM-oriented, and seemingly nice, but has (and leads to) annoying issues, partially caused by nuances of XMPP resource handling by clients. Leads to message loss all too often, with different client combinations.
OMEMO (deferred XEP-0384), which provides forward secrecy like OTR, offline and multi-user messages like OpenPGP, using a relatively new double ratchet algorithm developed for Signal, with some vendor-specific bits in the XEP (and its homepage is just a single page with little information on the Conversations website). The properties are nice, but no standalone specification or white paper in sight (it just relies on Signal protocol's specification). But there is a handy OMEMO integration tracker. Though it seems that the client incompabilities lead to message loss without user-visible traces at the moment, even after attempts to disable OMEMO; the kind of thing that draws users away from XMPP.
MLS will probably be standardized in the future, likely there will be a XEP, and hopefully it would solve the issues present in other options.

XMPP Protocol Guidelines provide a nice summary of useful features as well.


Here is a summary, based on both descriptions/documentation and source code of the implementations (since rather often it's either not documented, or the documentation is imprecise):

Implementation SCRAM EXTERNAL Acks Carbons C API Language
libpurple +-±++ C
Prosody ++++n/aLua
jabberd2 +---n/aC
bitlbee +--+n/aC
weechat/jabber.py --?-n/aC/Python
mcabber/loudmouth ----+ C
Conversations ++++n/aJava
ChatSecure/XMPPFramework +-+±n/aJava
Profanity/libstrophe +--±+ C
Psi/iris +?++n/aC++
Vacuum-IM ---+n/aC++
pontarius-xmpp +---- Haskell
Gajim/nbxmpp ++++- Python
Dino +?++n/aVala
gloox -+++- C++
Swift/Swiften ++++- C++
SleekXMPP/slixmpp ++++- Python
rexmpp +++++ C

And brief comments:

Has community modules, which should be enabled explicitly. Fortunately, it's nicely extensible, and there is plenty of modules.
Implements a very dated version of XEP-0198 (about 10 years old; it didn't even have a "draft" status back then); reported, but it also doesn't seem to be under active development, and has various other issues.
libpurple (Pidgin, bitlbee, etc)
Doesn't focus heavily on XMPP, hence lacks many features. I submitted a patch for XEP-0198 there, but it'll only be available since version 2.14 (that's quite a lag between implementation and availability: more than a year, without counting usual multi-year lags of stable distributions). And while C API is provided, it relies on Glib main loop, callbacks, C structures, Glib signals – making it rather hard to write bindings for other languages.
bitlbee's own XMPP implementation
Seems to have even more limited SASL support than that of libpurple, and also has issues similar to those of libpurple, caused by its API (which bitlbee reuses for its implementation as well): XMPP streams aren't getting closed properly there either, potentially leading to message loss in conditions where it shouldn't happen.
weechat's jabber.py
Uses an old and abandoned Python library (xmpppy), which implements a now-obsolete RFC even for the core; there are just PLAIN and DIGEST-MD5 authentication mechanisms (SCRAM is required to be available for authentication by the current specification).
mcabber's loudmouth library
Doesn't seem to support client certificates, or XEP-0198, or SCRAM.
Emacs's jabber.el
Uses sasl.el, but that doesn't include EXTERNAL. Also no XEP-0198. And it looks abandoned, too.
An Android client in Java which I've checked out of curiosity, does support client certificates and XEP-0198, and many other things. It also has documented observations on implementing XMPP. Though has some warts, such as long if-else-if chains, disconnecting after Integer.MAX_VALUE of stanzas is reached, and apparently more.
ChatSecure's XMPPFramework
Doesn't seem to support SASL EXTERNAL, but supports XEP-0198. But it's just for mobile devices (and just for iOS, as of recently). Carbons are implemented in ChatSecure, but not in XMPPFramework.
Both look nice at a glance, but no SASL EXTERNAL mechanism in libstrophe, and XEP-0198 implementation got stuck between libstrophe and Profanity for more than 2 years now. Carbons are implemented in profanity, but not in libstrophe.
A C++ monster, but relatively feature-rich.
A smaller C++ monster, with SASLFeatureFactory and such; seems to only support ANONYMOUS, PLAIN, and DIGEST-MD5 (roughly as with weechat), so not even quite a valid XMPP implementation. No XEP-0198 in sight.
A Haskell client library, but checked it at once: there are just PLAIN, DIGEST-MD5, and SCRAM-SHA-1. No XEP-0198, and apparently it's tricky to add there.
Supports plenty of XEPs, including 0198, and various SASL mechanisms, apparently including EXTERNAL. OTR and OMEMO are available via plugins, and OpenPGP – by default. Pretty good overall, apart from UI (which is actually fine, just not Emacs), and no apparent way to hook it into Emacs. There is a D-Bus interface, though it doesn't include events such as new message receiving.
I didn't check it closely, but it claims to support XEP-0198, doesn't seem to support OTR, but supports OMEMO, and no SASL EXTERNAL in sight. The UI looks rather appalling to me, but probably it's fine for some users, and it's said to be rather feature-rich.
A C++ library without C API (hence not very reusable directly): supports a bunch of XEPs (including 0198), as well as SASL EXTERNAL, but no SCRAM (which is required by the standard).
Also a C++ library without C API, claims to be pretty good, seems to support XEP-0198, as well as SASL EXTERNAL and SCRAM-*. Much more of C++ than I'd be comfortable with, and apparently not much of documentation (had to check sources to find out what it supports – as with many client programs, but libraries are expected to provide better docs), but looks good functionality-wise.
SleekXMPP and slixmpp
A Python library and its fork: also not reusable as a library from arbitrary programs, but supports EXTERNAL and SCRAM methods, and many pluggable XEPs. Used by Poezio.
Telepathy's Gabble
While not included into the comparison (and probably wouldn't look well there: seems to lack at least XEP-0198, and PRs hanging with no activity for months), it is noteworthy for its reusability via a D-Bus interface.

Improving the software

As it often happens, the existing implementations are imperfect, and their architectures are restrictive, yet there's also too many of them – leading to a lot of effort duplication, and multiple half-baked implementations.

In this situation it doesn't seem wise to make new clients, libraries, or protocols, and perhaps more effort should be put into incremental improvement – which may be hard and boring, but still better than poorly reinventing the wheel yet again.

Although as of 2020, I started writing rexmpp, a reusable XMPP library providing an asynchronous C API and often-missing but important functionality.

Server configuration

I'm using Prosody, since it supports plenty of extensions and doesn't require too many resources, and generally nice/handy to use. In addition to all the "recommended" and "nice to have" modules in the configuration, I'm enabling "proxy65" to get reliable file transfer (for clients who are behind NAT) with XEP-0234: Jingle File Transfer (XEP-0260: Jingle SOCKS5 Bytestreams Transport Method; ICE-TCP would have worked as well, but only ICE-UDP seems to be specified/used for XMPP; XEP-0261: Jingle In-Band Bytestreams Transport Method should work too, but clients seem to fail to use it). The "smacks" module is important for reliable message delivery, "cloud_notify" may be handy for "pull notifications" on mobile phones, and "turncredentials" helps to point a TURN server if there is one for clients (which should provide relatively reliable Jingle calls; coturn is easy to set). The "muc" component should be enabled to provide multi-user chats (XEP-0045), and "http_upload" -- for HTTP file upload (XEP-0363).

Unfortunately Jingle XTLS was abandoned, and those SOCKS5 connections wouldn't be encrypted at all on their own (neither would ICE-UDP ones, but at least there's SRTP for encrypted audio/video calls). In-band bytestreams may be preferable for encrypted (even though less efficient) file transfers, but that's up to clients. XEP-0391: Jingle Encrypted Transports is another solution to this.