All the subsequent e-mails appear as replies to the first e-mail sent
(either the preamble or the first patch). E-mails can be seen as
-replies to a different e-mail by using the '--refid' option.
+replies to a different e-mail by using the '--in-reply-to' option.
SMTP authentication is also possible with '--smtp-user' and
'--smtp-password' options, also available as configuration settings:
short = 'Add BCC to the Bcc: list'),
opt('--auto', action = 'store_true',
short = 'Automatically cc the patch signers'),
- opt('--noreply', action = 'store_true',
+ opt('--no-thread', action = 'store_true',
short = 'Do not send subsequent messages as replies'),
opt('--unrelated', action = 'store_true',
short = 'Send patches without sequence numbering'),
short = 'Edit each patch before sending'),
opt('-s', '--sleep', type = 'int', metavar = 'SECONDS',
short = 'Sleep for SECONDS between e-mails sending'),
- opt('--refid',
+ opt('--in-reply-to', metavar = 'REFID',
short = 'Use REFID as the reference id'),
opt('--smtp-server', metavar = 'HOST[:PORT] or "/path/to/sendmail -t -i"',
short = 'SMTP server or command to use for sending mail'),
opt('-b', '--branch', args = [argparse.stg_branches],
short = 'Use BRANCH instead of the default branch'),
opt('-m', '--mbox', action = 'store_true',
- short = 'Generate an mbox file instead of sending')
+ short = 'Generate an mbox file instead of sending'),
+ opt('--git', action = 'store_true',
+ short = 'Use git send-email (EXPERIMENTAL)')
] + argparse.diff_opts_option()
directory = DirectoryHasRepository(log = False)
cmd = sendmail.split()
Run(*cmd).raw_input(msg).discard_output()
-def __send_message_smtp(smtpserver, from_addr, to_addr_list, msg, options):
- """Send the message using the given SMTP server
+__smtp_credentials = None
+
+def __set_smtp_credentials(options):
+ """Set the (smtpuser, smtppassword, smtpusetls) credentials if the method
+ of sending is SMTP.
"""
+ global __smtp_credentials
+
+ smtpserver = options.smtp_server or config.get('stgit.smtpserver')
+ if options.mbox or options.git or smtpserver.startswith('/'):
+ return
+
smtppassword = options.smtp_password or config.get('stgit.smtppassword')
smtpuser = options.smtp_user or config.get('stgit.smtpuser')
smtpusetls = options.smtp_tls or config.get('stgit.smtptls') == 'yes'
if (smtpuser and not smtppassword):
smtppassword = getpass.getpass("Please enter SMTP password: ")
+ __smtp_credentials = (smtpuser, smtppassword, smtpusetls)
+
+def __send_message_smtp(smtpserver, from_addr, to_addr_list, msg, options):
+ """Send the message using the given SMTP server
+ """
+ smtpuser, smtppassword, smtpusetls = __smtp_credentials
+
try:
s = smtplib.SMTP(smtpserver)
except Exception, err:
s.quit()
+def __send_message_git(msg, options):
+ """Send the message using git send-email
+ """
+ from subprocess import call
+ from tempfile import mkstemp
+
+ cmd = ["git", "send-email", "--from=%s" % msg['From']]
+ cmd.append("--quiet")
+ cmd.append("--suppress-cc=self")
+ if not options.auto:
+ cmd.append("--suppress-cc=body")
+ if options.in_reply_to:
+ cmd.extend(["--in-reply-to", options.in_reply_to])
+ if options.no_thread:
+ cmd.append("--no-thread")
+
+ # We only support To/Cc/Bcc in git send-email for now.
+ for x in ['to', 'cc', 'bcc']:
+ if getattr(options, x):
+ cmd.extend('--%s=%s' % (x, a) for a in getattr(options, x))
+
+ (fd, path) = mkstemp()
+ os.write(fd, msg.as_string(options.mbox))
+ os.close(fd)
+
+ try:
+ try:
+ cmd.append(path)
+ call(cmd)
+ except Exception, err:
+ raise CmdException, str(err)
+ finally:
+ os.unlink(path)
+
def __send_message(type, tmpl, options, *args):
"""Message sending dispatcher.
"""
msg_id = email.Utils.make_msgid('stgit')
msg = build(tmpl, msg_id, options, *args)
- from_addr, to_addrs = __parse_addresses(msg)
msg_str = msg.as_string(options.mbox)
if options.mbox:
out.stdout_raw(msg_str + '\n')
return msg_id
- out.start('Sending ' + outstr)
+ if not options.git:
+ from_addr, to_addrs = __parse_addresses(msg)
+ out.start('Sending ' + outstr)
smtpserver = options.smtp_server or config.get('stgit.smtpserver')
- if smtpserver.startswith('/'):
+ if options.git:
+ __send_message_git(msg, options)
+ elif smtpserver.startswith('/'):
# Use the sendmail tool
__send_message_sendmail(smtpserver, msg_str)
else:
if type == 'cover' or (type == 'patch' and patch_nr < total_nr):
sleep = options.sleep or config.getint('stgit.smtpdelay')
time.sleep(sleep)
- out.done()
+ if not options.git:
+ out.done()
return msg_id
-def __build_address_headers(msg, options, extra_cc = []):
- """Build the address headers and check existing headers in the
- template.
- """
+def __update_header(msg, header, addr = '', ignore = ()):
def __addr_pairs(msg, header, extra):
pairs = email.Utils.getaddresses(msg.get_all(header, []) + extra)
# remove pairs without an address and resolve the aliases
return [address_or_alias(p) for p in pairs if p[1]]
- def __update_header(header, addr = '', ignore = ()):
- addr_pairs = __addr_pairs(msg, header, [addr])
- del msg[header]
- # remove the duplicates and filter the addresses
- addr_dict = dict((addr, email.Utils.formataddr((name, addr)))
- for name, addr in addr_pairs if addr not in ignore)
- if addr_dict:
- msg[header] = ', '.join(addr_dict.itervalues())
- return set(addr_dict.iterkeys())
+ addr_pairs = __addr_pairs(msg, header, [addr])
+ del msg[header]
+ # remove the duplicates and filter the addresses
+ addr_dict = dict((addr, email.Utils.formataddr((name, addr)))
+ for name, addr in addr_pairs if addr not in ignore)
+ if addr_dict:
+ msg[header] = ', '.join(addr_dict.itervalues())
+ return set(addr_dict.iterkeys())
+def __build_address_headers(msg, options, extra_cc = []):
+ """Build the address headers and check existing headers in the
+ template.
+ """
to_addr = ''
cc_addr = ''
extra_cc_addr = ''
bcc_addr = autobcc
# if an address is on a header, ignore it from the rest
- to_set = __update_header('To', to_addr)
- cc_set = __update_header('Cc', cc_addr, to_set)
- bcc_set = __update_header('Bcc', bcc_addr, to_set.union(cc_set))
+ to_set = __update_header(msg, 'To', to_addr)
+ cc_set = __update_header(msg, 'Cc', cc_addr, to_set)
+ bcc_set = __update_header(msg, 'Bcc', bcc_addr, to_set.union(cc_set))
# --auto generated addresses, don't include the sender
- from_set = __update_header('From')
- __update_header('Cc', extra_cc_addr, to_set.union(bcc_set).union(from_set))
-
- # update other address headers
- __update_header('Reply-To')
- __update_header('Mail-Reply-To')
- __update_header('Mail-Followup-To')
+ from_set = __update_header(msg, 'From')
+ __update_header(msg, 'Cc', extra_cc_addr,
+ to_set.union(bcc_set).union(from_set))
def __get_signers_list(msg):
"""Return the address list generated from signed-off-by and
msg['References'] = ref_id
msg['User-Agent'] = 'StGit/%s' % version.version
+ # update other address headers
+ __update_header(msg, 'Reply-To')
+ __update_header(msg, 'Mail-Reply-To')
+ __update_header(msg, 'Mail-Followup-To')
+
+
def __encode_message(msg):
# 7 or 8 bit encoding
charset = email.Charset.Charset('utf-8')
except Exception, ex:
raise CmdException, 'template parsing error: %s' % str(ex)
- __build_address_headers(msg, options)
- __build_extra_headers(msg, msg_id, options.refid)
+ if not options.git:
+ __build_address_headers(msg, options)
+ __build_extra_headers(msg, msg_id, options.in_reply_to)
__encode_message(msg)
return msg
else:
extra_cc = []
- __build_address_headers(msg, options, extra_cc)
+ if not options.git:
+ __build_address_headers(msg, options, extra_cc)
__build_extra_headers(msg, msg_id, ref_id)
__encode_message(msg)
if total_nr == 0:
raise CmdException, 'No patches to send'
- if options.refid:
- if options.noreply or options.unrelated:
+ if options.in_reply_to:
+ if options.no_thread or options.unrelated:
raise CmdException, \
- '--refid option not allowed with --noreply or --unrelated'
- ref_id = options.refid
+ '--in-reply-to option not allowed with --no-thread or --unrelated'
+ ref_id = options.in_reply_to
else:
ref_id = None
+ # get username/password if sending by SMTP
+ __set_smtp_credentials(options)
# send the cover message (if any)
if options.cover or options.edit_cover:
msg_id = __send_message('cover', tmpl, options, patches)
# subsequent e-mails are seen as replies to the first one
- if not options.noreply:
+ if not options.no_thread:
ref_id = msg_id
# send the patches
msg_id = __send_message('patch', tmpl, options, p, n, total_nr, ref_id)
# subsequent e-mails are seen as replies to the first one
- if not options.noreply and not options.unrelated and not ref_id:
+ if not options.no_thread and not options.unrelated and not ref_id:
ref_id = msg_id