91 **self._sslkwargs) |
92 **self._sslkwargs) |
92 self.file = smtplib.SSLFakeFile(new_socket) |
93 self.file = smtplib.SSLFakeFile(new_socket) |
93 return new_socket |
94 return new_socket |
94 else: |
95 else: |
95 def SMTPS(sslkwargs, keyfile=None, certfile=None, **kwargs): |
96 def SMTPS(sslkwargs, keyfile=None, certfile=None, **kwargs): |
96 raise util.Abort(_('SMTPS requires Python 2.6 or later')) |
97 raise error.Abort(_('SMTPS requires Python 2.6 or later')) |
97 |
98 |
98 def _smtp(ui): |
99 def _smtp(ui): |
99 '''build an smtp connection and return a function to send mail''' |
100 '''build an smtp connection and return a function to send mail''' |
100 local_hostname = ui.config('smtp', 'local_hostname') |
101 local_hostname = ui.config('smtp', 'local_hostname') |
101 tls = ui.config('smtp', 'tls', 'none') |
102 tls = ui.config('smtp', 'tls', 'none') |
102 # backward compatible: when tls = true, we use starttls. |
103 # backward compatible: when tls = true, we use starttls. |
103 starttls = tls == 'starttls' or util.parsebool(tls) |
104 starttls = tls == 'starttls' or util.parsebool(tls) |
104 smtps = tls == 'smtps' |
105 smtps = tls == 'smtps' |
105 if (starttls or smtps) and not util.safehasattr(socket, 'ssl'): |
106 if (starttls or smtps) and not util.safehasattr(socket, 'ssl'): |
106 raise util.Abort(_("can't use TLS: Python SSL support not installed")) |
107 raise error.Abort(_("can't use TLS: Python SSL support not installed")) |
107 mailhost = ui.config('smtp', 'host') |
108 mailhost = ui.config('smtp', 'host') |
108 if not mailhost: |
109 if not mailhost: |
109 raise util.Abort(_('smtp.host not configured - cannot send mail')) |
110 raise error.Abort(_('smtp.host not configured - cannot send mail')) |
110 verifycert = ui.config('smtp', 'verifycert', 'strict') |
111 verifycert = ui.config('smtp', 'verifycert', 'strict') |
111 if verifycert not in ['strict', 'loose']: |
112 if verifycert not in ['strict', 'loose']: |
112 if util.parsebool(verifycert) is not False: |
113 if util.parsebool(verifycert) is not False: |
113 raise util.Abort(_('invalid smtp.verifycert configuration: %s') |
114 raise error.Abort(_('invalid smtp.verifycert configuration: %s') |
114 % (verifycert)) |
115 % (verifycert)) |
115 verifycert = False |
116 verifycert = False |
116 if (starttls or smtps) and verifycert: |
117 if (starttls or smtps) and verifycert: |
117 sslkwargs = sslutil.sslkwargs(ui, mailhost) |
118 sslkwargs = sslutil.sslkwargs(ui, mailhost) |
118 else: |
119 else: |
149 ui.note(_('(authenticating to mail server as %s)\n') % |
150 ui.note(_('(authenticating to mail server as %s)\n') % |
150 (username)) |
151 (username)) |
151 try: |
152 try: |
152 s.login(username, password) |
153 s.login(username, password) |
153 except smtplib.SMTPException as inst: |
154 except smtplib.SMTPException as inst: |
154 raise util.Abort(inst) |
155 raise error.Abort(inst) |
155 |
156 |
156 def send(sender, recipients, msg): |
157 def send(sender, recipients, msg): |
157 try: |
158 try: |
158 return s.sendmail(sender, recipients, msg) |
159 return s.sendmail(sender, recipients, msg) |
159 except smtplib.SMTPRecipientsRefused as inst: |
160 except smtplib.SMTPRecipientsRefused as inst: |
160 recipients = [r[1] for r in inst.recipients.values()] |
161 recipients = [r[1] for r in inst.recipients.values()] |
161 raise util.Abort('\n' + '\n'.join(recipients)) |
162 raise error.Abort('\n' + '\n'.join(recipients)) |
162 except smtplib.SMTPException as inst: |
163 except smtplib.SMTPException as inst: |
163 raise util.Abort(inst) |
164 raise error.Abort(inst) |
164 |
165 |
165 return send |
166 return send |
166 |
167 |
167 def _sendmail(ui, sender, recipients, msg): |
168 def _sendmail(ui, sender, recipients, msg): |
168 '''send mail using sendmail.''' |
169 '''send mail using sendmail.''' |
172 ui.note(_('sending mail: %s\n') % cmdline) |
173 ui.note(_('sending mail: %s\n') % cmdline) |
173 fp = util.popen(cmdline, 'w') |
174 fp = util.popen(cmdline, 'w') |
174 fp.write(msg) |
175 fp.write(msg) |
175 ret = fp.close() |
176 ret = fp.close() |
176 if ret: |
177 if ret: |
177 raise util.Abort('%s %s' % ( |
178 raise error.Abort('%s %s' % ( |
178 os.path.basename(program.split(None, 1)[0]), |
179 os.path.basename(program.split(None, 1)[0]), |
179 util.explainexit(ret)[0])) |
180 util.explainexit(ret)[0])) |
180 |
181 |
181 def _mbox(mbox, sender, recipients, msg): |
182 def _mbox(mbox, sender, recipients, msg): |
182 '''write mails to mbox''' |
183 '''write mails to mbox''' |
206 def validateconfig(ui): |
207 def validateconfig(ui): |
207 '''determine if we have enough config data to try sending email.''' |
208 '''determine if we have enough config data to try sending email.''' |
208 method = ui.config('email', 'method', 'smtp') |
209 method = ui.config('email', 'method', 'smtp') |
209 if method == 'smtp': |
210 if method == 'smtp': |
210 if not ui.config('smtp', 'host'): |
211 if not ui.config('smtp', 'host'): |
211 raise util.Abort(_('smtp specified as email transport, ' |
212 raise error.Abort(_('smtp specified as email transport, ' |
212 'but no smtp host configured')) |
213 'but no smtp host configured')) |
213 else: |
214 else: |
214 if not util.findexe(method): |
215 if not util.findexe(method): |
215 raise util.Abort(_('%r specified as email transport, ' |
216 raise error.Abort(_('%r specified as email transport, ' |
216 'but not in PATH') % method) |
217 'but not in PATH') % method) |
217 |
218 |
218 def mimetextpatch(s, subtype='plain', display=False): |
219 def mimetextpatch(s, subtype='plain', display=False): |
219 '''Return MIME message suitable for a patch. |
220 '''Return MIME message suitable for a patch. |
220 Charset will be detected as utf-8 or (possibly fake) us-ascii. |
221 Charset will be detected as utf-8 or (possibly fake) us-ascii. |
300 acc, dom = addr.split('@') |
301 acc, dom = addr.split('@') |
301 acc = acc.encode('ascii') |
302 acc = acc.encode('ascii') |
302 dom = dom.decode(encoding.encoding).encode('idna') |
303 dom = dom.decode(encoding.encoding).encode('idna') |
303 addr = '%s@%s' % (acc, dom) |
304 addr = '%s@%s' % (acc, dom) |
304 except UnicodeDecodeError: |
305 except UnicodeDecodeError: |
305 raise util.Abort(_('invalid email address: %s') % addr) |
306 raise error.Abort(_('invalid email address: %s') % addr) |
306 except ValueError: |
307 except ValueError: |
307 try: |
308 try: |
308 # too strict? |
309 # too strict? |
309 addr = addr.encode('ascii') |
310 addr = addr.encode('ascii') |
310 except UnicodeDecodeError: |
311 except UnicodeDecodeError: |
311 raise util.Abort(_('invalid local address: %s') % addr) |
312 raise error.Abort(_('invalid local address: %s') % addr) |
312 return email.Utils.formataddr((name, addr)) |
313 return email.Utils.formataddr((name, addr)) |
313 |
314 |
314 def addressencode(ui, address, charsets=None, display=False): |
315 def addressencode(ui, address, charsets=None, display=False): |
315 '''Turns address into RFC-2047 compliant header.''' |
316 '''Turns address into RFC-2047 compliant header.''' |
316 if display or not address: |
317 if display or not address: |