diff --git a/mercurial/mail.py b/mercurial/mail.py --- 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):