diff --git a/mercurial/mail.py b/mercurial/mail.py
index 0b569c75d1808f05056e3e779993186ceded830f_bWVyY3VyaWFsL21haWwucHk=..83c0d144ef8d929de662dc5cbdead4127251c35c_bWVyY3VyaWFsL21haWwucHk= 100644
--- a/mercurial/mail.py
+++ b/mercurial/mail.py
@@ -151,6 +151,32 @@
     if starttls or smtps:
         ui.note(_(b'(verifying remote certificate)\n'))
         sslutil.validatesocket(s.sock)
+
+    try:
+        _smtp_login(ui, s, mailhost, mailport)
+    except smtplib.SMTPException as inst:
+        raise error.Abort(stringutil.forcebytestr(inst))
+
+    def send(sender, recipients, msg):
+        try:
+            return s.sendmail(sender, recipients, msg)
+        except smtplib.SMTPRecipientsRefused as inst:
+            recipients = [r[1] for r in inst.recipients.values()]
+            raise error.Abort(b'\n' + b'\n'.join(recipients))
+        except smtplib.SMTPException as inst:
+            raise error.Abort(inst)
+
+    return send
+
+
+def _smtp_login(ui, smtp, mailhost, mailport):
+    """A hook for the keyring extension to perform the actual SMTP login.
+
+    An already connected SMTP object of the proper type is provided, based on
+    the current configuration.  The host and port to which the connection was
+    established are provided for accessibility, since the SMTP object doesn't
+    provide an accessor.  ``smtplib.SMTPException`` is raised on error.
+    """
     username = ui.config(b'smtp', b'username')
     password = ui.config(b'smtp', b'password')
     if username:
@@ -163,21 +189,7 @@
     if username and password:
         ui.note(_(b'(authenticating to mail server as %s)\n') % username)
         username = encoding.strfromlocal(username)
-        try:
-            s.login(username, password)
-        except smtplib.SMTPException as inst:
-            raise error.Abort(stringutil.forcebytestr(inst))
-
-    def send(sender, recipients, msg):
-        try:
-            return s.sendmail(sender, recipients, msg)
-        except smtplib.SMTPRecipientsRefused as inst:
-            recipients = [r[1] for r in inst.recipients.values()]
-            raise error.Abort(b'\n' + b'\n'.join(recipients))
-        except smtplib.SMTPException as inst:
-            raise error.Abort(inst)
-
-    return send
+        smtp.login(username, password)
 
 
 def _sendmail(ui, sender, recipients, msg):