diff --git a/lib/Network/Protocol/XMPP.hs b/lib/Network/Protocol/XMPP.hs
--- a/lib/Network/Protocol/XMPP.hs
+++ b/lib/Network/Protocol/XMPP.hs
@@ -58,6 +58,8 @@
 	, putStanza
 	, getStanza
 	, bindJID
+	, throwE
+	, catchE
 
 	-- ** Resuming sessions
 	, Session
diff --git a/lib/Network/Protocol/XMPP/Client.hs b/lib/Network/Protocol/XMPP/Client.hs
--- a/lib/Network/Protocol/XMPP/Client.hs
+++ b/lib/Network/Protocol/XMPP/Client.hs
@@ -19,8 +19,8 @@
 	) where
 
 import           Control.Monad ((>=>))
-import           Control.Monad.Error (throwError)
-import           Control.Monad.Trans (liftIO)
+import           Control.Monad.IO.Class (liftIO)
+import           Control.Monad.Trans.Except (runExceptT)
 import           Data.ByteString (ByteString)
 import           Data.Text (Text)
 import qualified System.IO as IO
@@ -32,7 +32,6 @@
 import qualified Network.Protocol.XMPP.JID as J
 import qualified Network.Protocol.XMPP.Monad as M
 import qualified Network.Protocol.XMPP.XML as X
-import           Network.Protocol.XMPP.ErrorT
 import           Network.Protocol.XMPP.Stanza
 import           Network.Protocol.XMPP.String (s)
 
@@ -70,9 +69,9 @@
 		M.putElement xmlStartTLS
 		void M.getElement
 		h <- M.getHandle
-		eitherTLS <- liftIO (runErrorT (H.startTLS h))
+		eitherTLS <- liftIO (runExceptT (H.startTLS h))
 		case eitherTLS of
-			Left err -> throwError (M.TransportError err)
+			Left err -> M.throwE (M.TransportError err)
 			Right tls -> M.restartXMPP (Just tls) (newStream sjid >>= m)
 
 authenticationMechanisms :: [F.Feature] -> [ByteString]
@@ -111,7 +110,7 @@
 
 	returnedJID <- case maybeJID of
 		Just x -> return x
-		Nothing -> throwError (M.InvalidBindResult bindResult)
+		Nothing -> M.throwE (M.InvalidBindResult bindResult)
 
 	-- Session
 	M.putStanza sessionStanza
diff --git a/lib/Network/Protocol/XMPP/Client/Authentication.hs b/lib/Network/Protocol/XMPP/Client/Authentication.hs
--- a/lib/Network/Protocol/XMPP/Client/Authentication.hs
+++ b/lib/Network/Protocol/XMPP/Client/Authentication.hs
@@ -21,7 +21,6 @@
 import qualified Control.Exception as Exc
 import           Control.Monad (when)
 import           Control.Monad.IO.Class (MonadIO, liftIO)
-import qualified Control.Monad.Error as E
 import           Data.ByteString (ByteString)
 import qualified Data.ByteString.Char8
 import qualified Data.Text
@@ -49,7 +48,8 @@
              -> Text -- ^ Password
              -> M.XMPP ()
 authenticate xmppMechanisms userJID serverJID username password = xmpp where
-	mechanisms = map SASL.Mechanism xmppMechanisms
+	-- Filter out PLUS mechanisms because we haven't implemented channel binding
+	mechanisms = map SASL.Mechanism $ filter (not . ((Data.ByteString.Char8.pack "PLUS") `Data.ByteString.Char8.isSuffixOf`)) xmppMechanisms
 	authz = formatJID (userJID { jidResource = Nothing })
 	hostname = formatJID serverJID
 
@@ -62,9 +62,9 @@
 				Just mechanism -> authSasl ctx mechanism
 		case res of
 			Right Success -> return ()
-			Right (Failure e) -> E.throwError (M.AuthenticationFailure e)
-			Left (XmppError err) -> E.throwError err
-			Left (SaslError err) -> E.throwError (M.AuthenticationError err)
+			Right (Failure e) -> M.throwE (M.AuthenticationFailure e)
+			Left (XmppError err) -> M.throwE err
+			Left (SaslError err) -> M.throwE (M.AuthenticationError err)
 
 	authSasl ctx mechanism = do
 		let (SASL.Mechanism mechBytes) = mechanism
diff --git a/lib/Network/Protocol/XMPP/Component.hs b/lib/Network/Protocol/XMPP/Component.hs
--- a/lib/Network/Protocol/XMPP/Component.hs
+++ b/lib/Network/Protocol/XMPP/Component.hs
@@ -20,7 +20,8 @@
 
 import           Control.Applicative ((<|>))
 import           Control.Monad (when)
-import           Control.Monad.Error (throwError)
+import           Control.Monad.IO.Class (liftIO)
+import qualified Control.Monad.Trans.Except as E
 import           Data.Bits (shiftR, (.&.))
 import           Data.Char (intToDigit)
 import qualified Data.ByteString
@@ -28,8 +29,8 @@
 import qualified Data.Text
 import           Data.Text (Text)
 import           Data.Text.Encoding (encodeUtf8)
-import           Network.Protocol.SASL.GNU (sha1)
 import qualified System.IO as IO
+import qualified Network.Protocol.TLS.GNU as TLS (DigestAlgorithm(SHA1), hash)
 
 import qualified Network.Protocol.XMPP.Connections as C
 import qualified Network.Protocol.XMPP.Handle as H
@@ -57,7 +58,7 @@
 	M.putBytes $ C.xmlHeader (s"jabber:component:accept") jid
 	events <- M.readEvents C.startOfStream
 	case parseStreamID $ last events of
-		Nothing -> throwError M.NoComponentStreamID
+		Nothing -> M.throwE M.NoComponentStreamID
 		Just x -> return x
 
 parseStreamID :: X.Event -> Maybe Text
@@ -71,11 +72,15 @@
 authenticate :: Text -> Text -> M.XMPP ()
 authenticate streamID password = do
 	let bytes = buildSecret streamID password
-	let digest = showDigest (sha1 bytes)
-	M.putElement (X.element (s"handshake") [] [X.NodeContent (X.ContentText digest)])
-	result <- M.getElement
-	let nameHandshake = s"{jabber:component:accept}handshake"
-	when (null (X.isNamed nameHandshake result)) (throwError (M.AuthenticationFailure result))
+	msha1 <- liftIO $ E.runExceptT $ TLS.hash TLS.SHA1 bytes
+        case msha1 of
+		Left e -> M.throwE (M.AuthenticationError (Data.Text.pack $ show e))
+                Right sha1 -> do
+			let digest = showDigest sha1
+			M.putElement (X.element (s"handshake") [] [X.NodeContent (X.ContentText digest)])
+			result <- M.getElement
+			let nameHandshake = s"{jabber:component:accept}handshake"
+			when (null (X.isNamed nameHandshake result)) (M.throwE (M.AuthenticationFailure result))
 
 buildSecret :: Text -> Text -> ByteString
 buildSecret sid password = encodeUtf8 (X.escape (Data.Text.append sid password))
diff --git a/lib/Network/Protocol/XMPP/ErrorT.hs b/lib/Network/Protocol/XMPP/ErrorT.hs
deleted file mode 100644
--- a/lib/Network/Protocol/XMPP/ErrorT.hs
+++ /dev/null
@@ -1,87 +0,0 @@
-{-# LANGUAGE TypeFamilies #-}
-
--- Copyright (C) 2010-2011 John Millikin <jmillikin@gmail.com>
--- 
--- This program is free software: you can redistribute it and/or modify
--- it under the terms of the GNU General Public License as published by
--- the Free Software Foundation, either version 3 of the License, or
--- any later version.
--- 
--- This program is distributed in the hope that it will be useful,
--- but WITHOUT ANY WARRANTY; without even the implied warranty of
--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--- GNU General Public License for more details.
--- 
--- You should have received a copy of the GNU General Public License
--- along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-module Network.Protocol.XMPP.ErrorT
-	( ErrorT (..)
-	, mapErrorT
-	) where
-
-import           Control.Applicative (Applicative, pure, (<*>))
-import           Control.Monad.Fix (MonadFix, mfix)
-import           Control.Monad.Trans (MonadIO, liftIO)
-import           Control.Monad.Trans.Class (MonadTrans, lift)
-import qualified Control.Monad.Error as E
-import           Control.Monad.Error (ErrorType)
-import qualified Control.Monad.Reader as R
-import           Control.Monad.Reader (EnvType)
-
--- A custom version of ErrorT, without the 'Error' class restriction.
-
-newtype ErrorT e m a = ErrorT { runErrorT :: m (Either e a) }
-
-instance Functor m => Functor (ErrorT e m) where
-	fmap f = ErrorT . fmap (fmap f) . runErrorT
-
-instance (Functor m, Monad m) => Applicative (ErrorT e m) where
-	pure a  = ErrorT $ return (Right a)
-	f <*> v = ErrorT $ do
-		mf <- runErrorT f
-		case mf of
-			Left  e -> return (Left e)
-			Right k -> do
-				mv <- runErrorT v
-				case mv of
-					Left  e -> return (Left e)
-					Right x -> return (Right (k x))
-
-instance Monad m => Monad (ErrorT e m) where
-	return = ErrorT . return . Right
-	(>>=) m k = ErrorT $ do
-		x <- runErrorT m
-		case x of
-			Left l -> return (Left l)
-			Right r -> runErrorT (k r)
-
-instance Monad m => E.MonadError (ErrorT e m) where
-	type ErrorType (ErrorT e m) = e
-	throwError = ErrorT . return . Left
-	catchError m h = ErrorT $ do
-		x <- runErrorT m
-		case x of
-			Left l -> runErrorT (h l)
-			Right r -> return (Right r)
-
-instance MonadTrans (ErrorT e) where
-	lift = ErrorT . fmap Right
-
-instance R.MonadReader m => R.MonadReader (ErrorT e m) where
-	type EnvType (ErrorT e m) = EnvType m
-	ask = lift R.ask
-	local = mapErrorT . R.local
-
-instance MonadIO m => MonadIO (ErrorT e m) where
-	liftIO = lift . liftIO
-
-instance MonadFix m => MonadFix (ErrorT e m) where
-	mfix f = ErrorT $ mfix $ \ex -> runErrorT $ f $ case ex of
-		Right x -> x
-		_        -> error "empty mfix parameter"
-
-mapErrorT :: (m (Either e a) -> n (Either e' b))
-           -> ErrorT e m a
-           -> ErrorT e' n b
-mapErrorT f m = ErrorT (f (runErrorT m))
diff --git a/lib/Network/Protocol/XMPP/Handle.hs b/lib/Network/Protocol/XMPP/Handle.hs
--- a/lib/Network/Protocol/XMPP/Handle.hs
+++ b/lib/Network/Protocol/XMPP/Handle.hs
@@ -22,8 +22,8 @@
 	) where
 
 import           Control.Monad (when, void)
-import qualified Control.Monad.Error as E
-import           Control.Monad.Trans (liftIO)
+import qualified Control.Monad.Trans.Except as E
+import           Control.Monad.IO.Class (liftIO)
 import qualified Data.ByteString
 import           Data.ByteString (ByteString)
 import qualified Data.ByteString.Lazy
@@ -31,36 +31,35 @@
 import           Data.Text (Text)
 import qualified System.IO as IO
 import qualified Network.Protocol.TLS.GNU as TLS
-import           Network.Protocol.XMPP.ErrorT
 import           Network.Protocol.XMPP.String (s)
 
 data Handle =
 	  PlainHandle IO.Handle
 	| SecureHandle IO.Handle TLS.Session
 
-liftTLS :: TLS.Session -> TLS.TLS a -> ErrorT Text IO a
+liftTLS :: TLS.Session -> TLS.TLS a -> E.ExceptT Text IO a
 liftTLS session = liftTLS' . TLS.runTLS session
 
-liftTLS' :: IO (Either TLS.Error a) -> ErrorT Text IO a
+liftTLS' :: IO (Either TLS.Error a) -> E.ExceptT Text IO a
 liftTLS' io = do
 	eitherX <- liftIO io
 	case eitherX of
-		Left err -> E.throwError (Data.Text.pack (show err))
+		Left err -> E.throwE (Data.Text.pack (show err))
 		Right x -> return x
 
-startTLS :: Handle -> ErrorT Text IO Handle
-startTLS (SecureHandle _ _) = E.throwError $ s"Can't start TLS on a secure handle"
+startTLS :: Handle -> E.ExceptT Text IO Handle
+startTLS (SecureHandle _ _) = E.throwE $ s"Can't start TLS on a secure handle"
 startTLS (PlainHandle h) = liftTLS' $ TLS.runClient (TLS.handleTransport h) $ do
 	TLS.setCredentials =<< TLS.certificateCredentials
 	TLS.handshake
 	SecureHandle h `fmap` TLS.getSession
 
-hPutBytes :: Handle -> ByteString -> ErrorT Text IO ()
+hPutBytes :: Handle -> ByteString -> E.ExceptT Text IO ()
 hPutBytes (PlainHandle h)  = liftIO . Data.ByteString.hPut h
 hPutBytes (SecureHandle _ session) = liftTLS session . TLS.putBytes . toLazy where
 	toLazy bytes = Data.ByteString.Lazy.fromChunks [bytes]
 
-hGetBytes :: Handle -> Integer -> ErrorT Text IO ByteString
+hGetBytes :: Handle -> Integer -> E.ExceptT Text IO ByteString
 hGetBytes (PlainHandle h) n = liftIO (Data.ByteString.hGet h (fromInteger n))
 hGetBytes (SecureHandle h session) n = liftTLS session $ do
 	pending <- TLS.checkPending
@@ -68,9 +67,9 @@
 	when (pending == 0) (liftIO wait)
 	Data.ByteString.concat . Data.ByteString.Lazy.toChunks <$> getBytes
 	where
-	getBytes = TLS.getBytes n `E.catchError` handleGetBytesErr
+	getBytes = TLS.getBytes n `E.catchE` handleGetBytesErr
 	handleGetBytesErr (TLS.Error (-28)) = getBytes
-	handleGetBytesErr e = E.throwError e
+	handleGetBytesErr e = E.throwE e
 
 handleIsSecure :: Handle -> Bool
 handleIsSecure PlainHandle{} = False
diff --git a/lib/Network/Protocol/XMPP/JID.hs b/lib/Network/Protocol/XMPP/JID.hs
--- a/lib/Network/Protocol/XMPP/JID.hs
+++ b/lib/Network/Protocol/XMPP/JID.hs
@@ -30,6 +30,7 @@
 import qualified Data.Text
 import           Data.Text (Text)
 import qualified Data.Text.IDN.StringPrep as SP
+import qualified Data.Text.IDN.IDNA as IDNA
 import           Data.String (IsString, fromString)
 
 newtype Node = Node { strNode :: Text }
@@ -73,28 +74,32 @@
 
 parseJID :: Text -> Maybe JID
 parseJID str = maybeJID where
-	(node, postNode) = case textSpanBy (/= '@') str of
+	(bare, resource) = case textSpanBy (/= '/') str of
 		(x, y) -> if Data.Text.null y
-			then (Data.Text.empty, x)
-			else (x, Data.Text.drop 1 y)
-	(domain, resource) = case textSpanBy (/= '/') postNode of
+			then (x, Nothing)
+			else (x, Just $ Data.Text.drop 1 y)
+	(node, domain) = case textSpanBy (/= '@') bare of
 		(x, y) -> if Data.Text.null y
-			then (x, Data.Text.empty)
-			else (x, Data.Text.drop 1 y)
-	nullable x f = if Data.Text.null x
-		then Just Nothing
+			then (Nothing, x)
+			else (Just x, Data.Text.drop 1 y)
+	nullable Nothing _ = Just Nothing
+	nullable (Just x) f = if Data.Text.null x
+		then Nothing
 		else fmap Just (f x)
 	maybeJID = do
 		preppedNode <- nullable node (stringprepM SP.xmppNode)
-		preppedDomain <- stringprepM SP.nameprep domain
+		preppedDomain <- fmap (IDNA.toUnicode IDNA.defaultFlags)
+			(rightToJust $ IDNA.toASCII IDNA.defaultFlags domain)
 		preppedResource <- nullable resource (stringprepM SP.xmppResource)
-		return $ JID
-			(fmap Node preppedNode)
-			(Domain preppedDomain)
-			(fmap Resource preppedResource)
-	stringprepM p x = case SP.stringprep p SP.defaultFlags x of
-		Left _ -> Nothing
-		Right y -> Just y
+		if Data.Text.null preppedDomain
+			then Nothing
+			else return $ JID
+				(fmap Node preppedNode)
+				(Domain preppedDomain)
+				(fmap Resource preppedResource)
+	rightToJust (Left _) = Nothing
+	rightToJust (Right y) = Just y
+	stringprepM p x = rightToJust $ SP.stringprep p SP.defaultFlags x
 
 parseJID_ :: Text -> JID
 parseJID_ = fromMaybe (error "Malformed JID") . parseJID
diff --git a/lib/Network/Protocol/XMPP/Monad.hs b/lib/Network/Protocol/XMPP/Monad.hs
--- a/lib/Network/Protocol/XMPP/Monad.hs
+++ b/lib/Network/Protocol/XMPP/Monad.hs
@@ -1,5 +1,3 @@
-{-# LANGUAGE TypeFamilies #-}
-
 -- Copyright (C) 2010-2011 John Millikin <jmillikin@gmail.com>
 -- 
 -- This program is free software: you can redistribute it and/or modify
@@ -22,6 +20,8 @@
 	, runXMPP
 	, startXMPP
 	, restartXMPP
+        , throwE
+        , catchE
 
 	, getHandle
 	, getSession
@@ -41,16 +41,15 @@
 import qualified Control.Concurrent.MVar as M
 import           Control.Monad (ap)
 import           Control.Monad.Fix (MonadFix, mfix)
-import           Control.Monad.Trans (MonadIO, liftIO)
-import qualified Control.Monad.Error as E
-import           Control.Monad.Error (ErrorType)
-import qualified Control.Monad.Reader as R
+import           Control.Monad.IO.Class (MonadIO, liftIO)
+import           Control.Monad.Trans.Class (lift)
+import qualified Control.Monad.Trans.Except as E
+import qualified Control.Monad.Trans.Reader as R
 import qualified Data.ByteString
 import           Data.ByteString (ByteString)
 import           Data.Text (Text)
 import           Data.Text.Encoding (encodeUtf8)
 
-import           Network.Protocol.XMPP.ErrorT
 import qualified Network.Protocol.XMPP.Handle as H
 import qualified Network.Protocol.XMPP.Stanza as S
 import qualified Network.Protocol.XMPP.XML as X
@@ -90,7 +89,7 @@
 	, sessionWriteLock :: M.MVar ()
 	}
 
-newtype XMPP a = XMPP { unXMPP :: ErrorT Error (R.ReaderT Session IO) a }
+newtype XMPP a = XMPP { unXMPP :: E.ExceptT Error (R.ReaderT Session IO) a }
 
 instance Functor XMPP where
 	fmap f = XMPP . fmap f . unXMPP
@@ -102,11 +101,6 @@
 instance MonadIO XMPP where
 	liftIO = XMPP . liftIO
 
-instance E.MonadError XMPP where
-	type ErrorType XMPP = Error
-	throwError = XMPP . E.throwError
-	catchError m h = XMPP (E.catchError (unXMPP m) (unXMPP . h))
-
 instance A.Applicative XMPP where
 	pure = return
 	(<*>) = ap
@@ -115,7 +109,7 @@
 	mfix f = XMPP (mfix (unXMPP . f))
 
 runXMPP :: Session -> XMPP a -> IO (Either Error a)
-runXMPP session xmpp = R.runReaderT (runErrorT (unXMPP xmpp)) session
+runXMPP session xmpp = R.runReaderT (E.runExceptT (unXMPP xmpp)) session
 
 startXMPP :: H.Handle -> Text -> XMPP a -> IO (Either Error a)
 startXMPP h ns xmpp = do
@@ -129,7 +123,7 @@
 	Session oldH ns _ readLock writeLock <- getSession
 	sax <- liftIO X.newParser
 	let session = Session (fromMaybe oldH newH) ns sax readLock writeLock
-	XMPP (R.local (const session) (unXMPP xmpp))
+	XMPP $ E.ExceptT $ (R.local (const session) (E.runExceptT $ unXMPP xmpp))
 
 withLock :: (Session -> M.MVar ()) -> XMPP a -> XMPP a
 withLock getLock xmpp = do
@@ -137,11 +131,11 @@
 	let mvar = getLock session
 	res <- liftIO (M.withMVar mvar (const $ runXMPP session xmpp))
 	case res of
-		Left err -> E.throwError err
+		Left err -> XMPP $ E.throwE err
 		Right x -> return x
 
 getSession :: XMPP Session
-getSession = XMPP R.ask
+getSession = XMPP $ lift $ R.ask
 
 getHandle :: XMPP H.Handle
 getHandle = fmap sessionHandle getSession
@@ -149,11 +143,11 @@
 sessionIsSecure :: XMPP Bool
 sessionIsSecure = H.handleIsSecure <$> getHandle
 
-liftTLS :: ErrorT Text IO a -> XMPP a
+liftTLS :: E.ExceptT Text IO a -> XMPP a
 liftTLS io = do
-	res <- liftIO (runErrorT io)
+	res <- liftIO (E.runExceptT io)
 	case res of
-		Left err -> E.throwError (TransportError err)
+		Left err -> XMPP $ E.throwE (TransportError err)
 		Right x -> return x
 
 putBytes :: ByteString -> XMPP ()
@@ -177,7 +171,7 @@
 			let eof = Data.ByteString.null bytes
 			parsed <- liftIO (X.parse p bytes eof)
 			case parsed of
-				Left err -> E.throwError (TransportError err)
+				Left err -> XMPP $ E.throwE (TransportError err)
 				Right events -> return events
 		X.readEvents done nextEvents
 
@@ -187,7 +181,7 @@
 		events <- readEvents endOfTree
 		case X.eventsToElement events of
 			Just x -> return x
-			Nothing -> E.throwError (TransportError $ s"getElement: invalid event list")
+			Nothing -> XMPP $ E.throwE (TransportError $ s"getElement: invalid event list")
 
 	endOfTree 0 (X.EventEndElement _) = True
 	endOfTree _ _ = False
@@ -198,4 +192,10 @@
 	Session _ ns _ _ _ <- getSession
 	case S.elementToStanza ns elemt of
 		Just x -> return x
-		Nothing -> E.throwError (InvalidStanza elemt)
+		Nothing -> XMPP $ E.throwE (InvalidStanza elemt)
+
+throwE :: Error -> XMPP a
+throwE = XMPP . E.throwE
+
+catchE :: XMPP a -> (Error -> XMPP a) -> XMPP a
+catchE (XMPP m) h = XMPP (m `E.catchE` (unXMPP . h))
diff --git a/network-protocol-xmpp.cabal b/network-protocol-xmpp.cabal
--- a/network-protocol-xmpp.cabal
+++ b/network-protocol-xmpp.cabal
@@ -1,5 +1,5 @@
 name: network-protocol-xmpp
-version: 0.4.10
+version: 0.5.2
 license: GPL-3
 license-file: COPYING
 author: John Millikin <jmillikin@gmail.com>, Stephan Maka <stephan@spaceboyz.net>
@@ -21,7 +21,7 @@
 source-repository this
   type: git
   location: https://git.sr.ht/~singpolyma/network-protocol-xmpp
-  tag: 0.4.9
+  tag: 0.5.2
 
 library
   default-language: Haskell2010
@@ -32,10 +32,9 @@
       base >= 4.0 && < 5.0
     , bytestring >= 0.9
     , gnuidn >= 0.2 && < 0.3
-    , gnutls >= 0.1.4 && < 0.3
-    , gsasl >= 0.3 && < 0.4
+    , gnutls >= 0.1.4 && < 0.5
+    , gsasl >= 0.3 && < 0.6
     , libxml-sax >= 0.7 && < 0.8
-    , monads-tf >= 0.1 && < 0.2
     , network >= 3.0 && < 4.0
     , network-simple >= 0.4 && < 0.5
     , text >= 0.10
@@ -52,7 +51,6 @@
     Network.Protocol.XMPP.Client.Features
     Network.Protocol.XMPP.Component
     Network.Protocol.XMPP.Connections
-    Network.Protocol.XMPP.ErrorT
     Network.Protocol.XMPP.Handle
     Network.Protocol.XMPP.JID
     Network.Protocol.XMPP.Monad
