[Git]提交后自动发email

当然是通过hooks来实现了,对应post-receive,脚本也是已经随git-core安装就有了的:/usr/share/doc/git-core/contrib/hooks/post-receive-email,不过这个脚本用到了sendmail,我想好多机器上都没配这个东东吧,好在有好心人在这个脚本的基础上进行了完善,可以用msmtp发信了,看来我以前换用msmtp配mutt太正确了,另外msmtp也确实比sendmail小巧多了。

首先把刚才说到的脚本以及依赖文件functions一起下载到某地,加上执行属性(公用),然后ln到仓库的hooks目录下:

$ cd test.git/hooks/
$ mv post-receive post-receive.origin
$ ln -s ../../gittools/post-receive-email post-receive
$ ln -s ../../gittools/functions

然后修改仓库里的config文件,注意不是客户端的:

[hooks "post-receive-email"]
    mailinglist = list1@domain.tld, list2@domain.tld
    announcelist =
    envelopesender = mailsender@domain.tld
    sendmail = /usr/bin/msmtp

其中:

  • mailinglist 默认的收信人,留空就不发信了
  • announcelist 创建tag时发送从上次创建tag以来的汇总邮件的收信人,比如用版本号作为tag的时候这就生成了每个版本的changelog,留空则用mailinglist的值
  • envelopesender 发信人/账号,要和msmtp的发信账号对应起来
  • sendmail sendmail或其它发信程序的路径

还有个环境变量$USER_EMAIL,也是个发信人,不过是显示在邮件From:里的。如果要设置邮件里的From:,需要自己修改post-receive-email或在其之前执行的脚本,设置环境变量:

export USER_EMAIL="GIT <mailsender@domain.tld>"

这一版修改中作者还去掉了原来的emailprefix设置参数,固定为用仓库里description文件的内容加上[]替代。

最后,在git(git服务器运行用户)用户的HOME下放一个.msmtprc,配置发信认证信息:

defaults
    tls_trust_file /etc/ssl/certs/ca-certificates.crt
account gmail
    host smtp.gmail.com
    port 465
    auth on
    tls on
    tls_starttls off
account mailsender@domain.tld : gmail
#   from must be same as From: in mail, exclude Name, only mail address
#   Because maybe msmtp select account using from
    from mailsender@domain.tld
    user "mailsender@domain.tld"
    password my_passwd
account default : mailsender@domain.tld

现在就可以测试push,看自动发信是否正常了。如果提示functions语法错误,比如:

hooks/functions: 213: Syntax error: Bad for loop variable

可以把这两个脚本第一行的#!/bin/sh改为#!/bin/bash

注意msmtp调用的是提交动作所属用户的.msmtprc,从本机提交和远程ssh进来可能用的就不是一个.msmtprc了。

参考

[Mutt]用msmtp替代esmtp作发信代理

刚开始使用mutt的时候,由于也没有什么经验,在MDA选择方面抓了一个esmtp就用上了。说实话,esmtp也一直工作的很好,就是发信的时候需要傻傻等着(参见muttrc的sendmail_wait参数),如果不等待也可以,发送失败你就不知道了。虽然失败的情况比较少,一般都是邮件比较大或者网络不太好的情况才会发生,但我们外发的邮件往往都是比较重要的,真想有一种能够自动重试的发信代理,于是就查到了msmtp。

msmtpesmtp两个软件作者都不多,但msmtp确实更新频繁一些,而esmtp作者说现在已经不需要怎么添加功能了,只是维护bug。在多账户配置方面,好像msmtp的配置方法要“聪明”一些,账号规则有一些”继承”的小把戏。在发信队列方面,esmtp在Features中明显声明不支持,而msmtp有一个msmtpqueue,国内用的人非常少,只看到cu blog上提到了一点,smtpqueue能够把要外发的邮件集中在一起,单独发送,但没有说失败处理的事情;再到msmtp在sf.net上的cvs中查msmtpqueue的README文件,终于搞清楚了,和我的需要比较吻合。

msmtpqueue会”冒充”成一个MDA,当mutt发信时,它接收外发邮件并返回成功信息,而实际上只是把信件保存在QUEUEDIR里了,当调用msmtp-runqueue.sh的时候,再进行实际的发送处理。发送成功一封信,就会从QUEUEDIR中删除,发送失败就继续保持不动,下次再调用msmtp-runqueue.sh的时候自然又会处理(相当于重发)了。比起mutt中的邮件失败重发还会多生成一个邮件副本(我设定了发信的同时record在当前目录)应该是好多了。

Mails sent successfully will be deleted from the queue directory.
Mails whose delivery failed will be left untouched; you may want to edit
them, delete them by hand or simply run msmtp-runqueue.sh at a later time.

工作开始,首先通过apt安装msmtp,很小的,加上TLS/SSL所需的libgsasl7,一共才182k。然后配置账号文件~/.msmtprc,格式和~/.esmtprc比较类似:

# Default value for all following accounts
defaults
#      tls on
    tls_trust_file /etc/ssl/certs/ca-certificates.crt
#   keepbcc on
    logfile ~/log/msmtp.log

# Gmail
account gmail
    host smtp.gmail.com
    port 587
    auth on
    tls on

account mailbox@gmail.com : gmail
    from mailbox@gmail.com
    user "mailbox@gmail.com"
    password "secret"

# Another mail service
account another_mailbox@domain.com
    host smtp.domain.com
    auth on
    from another_mailbox@domain.com
    user "another_mailbox"
    password "another_secret"

# Default account
account default : mailbox@gmail.com

Copy自官方文档,语法很简单,最开始的defaults是默认设置,然后的account就是各个账号的设置了,账号名称最好和邮件中的From:对应,这样msmtp就能知道调用哪个账号了。最有意思的是,account可以用冒号:来”继承”其它已定义账号的设置,使用这个机制,就为所有gmail邮箱指定了host、port、auth、tls四个属性,然后在具体的账号设置中,只要再设定from、user、password就可以了,很方便,”继承”多个账号的话用逗号隔开。最后默认发信账号(匹配寻找account失败时使用)default可以直接”继承”某个账号的设置过来。

然后设置~/.muttrc,用msmtp来发信:

set sendmail="/path/to/msmtp"
set use_from=yes
set from="Fwolf <mailbox@domain.com>"
set envelope_from=yes
set sendmail_wait=0

测试一下,发信正常,现在可以让msmtpqueue出场了。由于msmtpqueue只是在”转达”msmtp发信的命令,所以需要先把msmtp调试好以后再配置。

msmtpqueue已经随msmtp安装上了,放在/usr/share/doc/msmtp/examples下,按照这里README文件的说明,把msmtp-enqueue.shmsmtp-runqueue.sh两个文件加上执行属性,然后ln到$HOME/.mutt下,再在这里创建一个新目录msmtpqueue,ln成~/.msmtpqueue(两个脚本默认的QUEUEDIR),最后修改muttrc中的sendmail:

set sendmail = "~/.mutt/msmtp-enqueue.sh"

好了,现在再来发信,是不是瞬间就完成了?再看~/.mutt/msmtpqueue目录下,也多了两个文件,分别以.mail.msmtp结尾,他们分别包含了刚才所发信件的信件内容和发送命令。现在运行msmtp-runqueue.sh

~/.mutt$ ./msmtp-runqueue.sh 
*** Sending 2008-01-12-23.03.52.mail...
2008-01-12-23.03.52.mail sent successfully

邮件就这样顺利的发出去了。

工作到这里基本就都完成了,发信时按y嗖一下就完成的感觉真不错,为了更方便的发送邮件,还可以在mutt中定义启动邮件发送程序的快捷键:

macro generic S "!~/.mutt/msmtp-runqueue.sh\n"

ubuntu的包里没有,但svn上还有一个msmtp-listqueue.sh脚本,列出当前QUEUEDIR中信件的From/To/主题,凑合能用,但用RFC2047编码方式的中文标题自然是不能正常显示的了。

Update @ 2009-03-27

知道gmail的两个端口,465和587有区别么?还真不完全一样,我用msmtp试出来的结果是这样的:

  • 如果使用465端口,则置tls_starttls off
  • 如果使用587端口,则置tls_starttls on

否则不是连不上就是无回馈数据。是看了标题: 我翻译的 msmtp 的手册页后受启发发现的。