1. 程式人生 > >crontab輸出內容傳送到指定郵箱

crontab輸出內容傳送到指定郵箱

YourCommand >tmpfile
cat tmpfile | mailx -s "Test Mail"  [email protected]
cat tmpfile >>YourLog
將這三句放到一個腳本里,在crontab執行這個指令碼

我開始老想著用一條很長的指令碼直接放到crontab裡執行實現我想要的功能,很傻

另外推薦給大家一個郵件客戶端小工具sendEmail,我在linux、aix、solaris下都能直接用,不需要安裝的綠色軟體,也不用鼓搗什麼sendmail了


crontab有一個郵件傳送的機制,如果crontab執行指令碼時,stdout有輸出時,會以郵件的形式傳送到crontab當前使用者,使用mail

命令即可檢視郵件。這些資訊經常很有用,往往攜帶了錯誤資訊,可以幫助管理員排錯,因此管理員對於mail不可不關注。

注意:

想要看到crontab報警郵件需要有郵件伺服器,在centos/RHEL,ubuntu/Debian等主流發行版都會有一個mailutils軟體包,這個軟體包就二選一依賴於郵件服務端軟體postfix/sendmail和客戶端軟體mail

(早一些的發行版,如centos/RHEL5 優先依賴的是sendmail,centos6,ubuntu12.04等新一些的發行版,優先依賴的是postfix)

安裝mailutils之後,預設配置即可收到crontab的郵件,使用mail命令即可看到郵件詳情。

但當伺服器比較多時,一臺臺ssh上去敲mail命令顯然不合適,有沒有方法能讓crontab把郵件傳送到管理員的郵箱呢?crontab已經有這種設定了。

研究了一天,google了一天老外的資料,眼睛都花了(希望自己動手解決的可以google一下各種關於crontab smtp之類的關鍵字,老外提到的基本集中在幾個點),加上自己的各種嘗試,總結方法如下:

MAILTO變數


首先值得關注的是MAILTO這個變數,這個在crontab的man手冊寫的也很清楚:

   In  addition  to  LOGNAME, HOME, and SHELL, cron(8
) will look at MAILTO if it has any reason to send mail as a result of running commands in ``this'' crontab. If MAILTO is defined (and non-empty), mail is sent to the user so named. MAILTO may also be used to direct mail to multiple recipients by separating recipient users with a comma. If MAILTO is defined but empty (MAILTO=""), no mail will be sent. Otherwise mail is sent to the owner of the crontab.

也就是說,定義了MAILTO這個變數,那麼crontab會將stdout的內容以郵件的形式傳送到MAILTO定義的郵箱中。

測試一下,編輯/etc/crontab,增加兩行:

MAILTO=myuser@mydomain.com
* * * * * root echo "mail test"

如果沒什麼問題的話,有可能會在一分鐘以後收到cron的郵件。

smtp


如果上面的方案能起作用的話,那麼恭喜你,你省了很多麻煩。下面我要說的就是我折騰了一天後才搞定的玩意——smtp

上面說有可能會收到郵件,是因為郵件傳送機制決定的,以下表述可能不準確,是按照我自己的理解來說的,可能會誤導。郵件的傳送方和接收方需要有域名,可以被DNS正確解析的。如果你的伺服器有域名,那麼恭喜你,只需掛上自己的域名,配置一下postfix/sendmail允許向外傳送郵件即可。如果沒有域名,或者伺服器在內網的話,這種方式就行不通了(這裡可能有誤,我有一臺伺服器在域名那裡直接寫的是主機IP,可以傳送出去。但是另一臺這樣做就不行,猜測是否跟IP能反解析有關)

下面介紹的是一種更通用的形式——smtp協議

首先需要裝smtp客戶端,老外推薦更多的是msmtp這個smtp客戶端,我的系統是ubuntu-server 12.04,以下命令全部都是ubuntu 12.04上可以用的命令,如果是其他發行版,做相應變更即可

使用smtp傳送郵件的話,那麼postfix/sendmail就不再需要了,可以解除安裝掉

apt-get purge postfix  #徹底解除安裝postfix(如果之前使用的服務端是sendmail的話就改成sendmail)
apt-get purge mailutils #徹底解除安裝mailutils,mail都發送到外部郵箱去了,因此mail命令也沒用了,如果還想在本地傳送郵件的話,保留也可以
apt-get auto-remove    #清理掉不再使用的依賴項

安裝msmtp

之後安裝msmtp,注意的是有兩個軟體包都要裝:

apt-get install msmtp-mta #只裝這一個就可以了,因為這個軟體包依賴於msmtp,會自動安裝。msmtp-mta這個軟體包會將/usr/sbin/sendmail --> /usr/bin/msmtp做一個軟連線,也就是會將原來使用sendmail傳送郵件的程式改為使用msmtp傳送。

如果此時安裝mailutils(可選),會發現由於存在/usr/sbin/sendmail,所以既不會安裝sendmail也不會安裝postfix。

配置msmtp

msmtp安裝完畢並不存在全域性配置檔案,需要時可以自己建立一個。具體的命令列語法就不多介紹了,看--help幫助就可以了。

msmtp支援全域性配置/etc/msmtprc和使用者個性配置~/.msmtprc,需要所有使用者使用同樣的msmtp配置的話,只建立/etc/msmtprc就可以了,以下是我的配置

vim /etc/msmtprc

defaults
logfile /var/log/msmtp.log  #注意許可權,普通使用者可能沒有寫入這個檔案的許可權,可以管理員授權
syslog on                #這個選項是記錄到syslog的,可以去掉這一行,預設是off
aliases /etc/aliases  #先看看這個檔案是否存在,如果不存在就不要加這一行,這一行的作用後面再說

account default
host smtp.ym.163.com
from user@domain.com
user user@domain.com
password mypass
auth on
tls on
tls_certcheck off

我的配置,使用網易企業郵箱的smtp伺服器傳送郵件的,開啟了tls。這裡根據需要自己調整,如果使用QQ郵箱或是gmail等其他郵箱,請參考郵箱幫助文件配置smtp。

配置完畢之後測試一下

msmtp -Sd看一下輸出,檢測一下變數,看看有沒有問題,傳送一封郵件試試echo -e "Subject: Test Mail\r\n\r\nThis is a test mail" |msmtp --debug -t youremail@domain ,看一下輸出,如果能收到郵件的話,那麼msmtp的配置就結束了。

使用msmtp替換sendmail,成為crontab傳送郵件的客戶端

只需安裝msmtp-mta這個軟體包即可,會自動做軟連線,上面提到過,如果沒裝的話,也可以手工軟連線/usr/lib/sendmail/usr/sbin/sendmail兩個檔案到/usr/bin/msmtp,之後如果crontab傳送郵件的時候,就會使用msmtp了。

遇到的問題

1:CRON[28742]: (root) MAIL (mailed 1 byte of output; but got status 0x004e, #012)

這是由於已經使用了smtp代替了sendmail/postfix,已經連線到了smtp伺服器上,smtp伺服器可不識別root、mail這樣的使用者名稱作為郵件地址,所以報錯了。配合開始提到的MAILTO變數,在crontab中寫入MAILTO這個變數,強制指定將郵件傳送到目標郵箱中即可。

2:中文亂碼,效果如下:

������ english
ls: ������������/asldkfjasdf: ���������������������������
LANG=zh_CN.UTF-8
LANGUAGE=zh_CN:zh
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=zh_CN.UTF-8

記得郵件有content type這個屬性嗎?設定為text/plain; charset=utf-8就可以搞定了。crontab有一個CONTENT_TYPE變數(詳見man 5 crontab,搜尋charset這個關鍵字即可找到相關內容),在crontab中定義CONTENT_TYPE=text/plain; charset=utf-8就可以了

依舊沒解決的問題


crontab全域性變數問題

試了很多次,發現所有的crontab檔案的環境變數都是獨立的,也就是說在/etc/crontab中定義的[email protected]並不會影響到crontab -e!依然需要在crontab -e中重新寫上[email protected],再加上系統中有各種拆散的crontab(如/etc/cron.d/,/etc/cron.daily等等)。

但是對於MAILTO這個變數問題,有一個變通的解決方案。

還記得在msmtp配置中提到的aliases /etc/aliases這個配置段嗎?根據msmtp的man手冊,這個代表使用指定檔案定義aliases,預設為空。

/etc/aliases這個檔案是sendmail的郵件別名,如果之前安裝過postfix/sendmail的話,是存在這個檔案的,指明瞭如果發到哪個使用者的郵件,自動使用別名命名成別的地址。

這個檔案的格式也很簡單user: email_address即可,如root: [email protected],這樣的話發到root的郵件就會自動被別名替換而傳送到[email protected]

我的配置: default: [email protected],default代表預設,即不指定的話,所有傳送到使用者的郵件都將被這個別名替換,這樣就不需要所有的crontab去指定MAILTO這個變量了,預設會發送到crontab使用者中,然後被別名替換。

但是對於CONTENT_TYPE這個變數我真的沒有什麼好辦法了,希望有朋友支招,只能一個個寫了……

所幸的是基本上只有自己寫的指令碼才有中文輸出,系統命令大多是英文的,所以暫時只把這個變數加到了crontab -e中,以後如果哪個出現中文亂碼了再在哪個crontab中加吧。

google到老外的一種解決方案,就是給cron守護程序傳遞引數,讓cron啟動的時候初始化環境變數,就會成為crontab中全域性變數,我看ubuntu的crontab的man手冊,也提到了自定義變數寫在/etc/default/corn中,但是開啟這個檔案,提示這個檔案已經不再支援了,如果有自定義變數的需求,寫入/etc/init/cron.conf/etc/init/cron.override,然後我就不會搞了,也沒google到別人怎麼寫cron.override的。希望有知道的朋友不吝賜教!


CentOS5.1裡oracle使用者的crontab:
00-59/2 * * * * /backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;cat /tmp/gzgaCronLog.log|sendmail [email protected] "GZGA Backup Mission Finished!"
我欲實現功能:1.指令碼/backupGZGA.sh被CRON自動呼叫執行完成後把整個執行過程中終端中產生的日誌及提示資訊輸入到\gzgaCronLog.log檔案中去,向[email protected]發個郵件標題為"GZGA Mission Finished."併發送附件gzgaCronLog.log. 

var/spool/mail的內容:
rom [email protected]  Tue Oct  7 17:32:13 2008
Return-Path: <[email protected]>
Received: from localhost.localdomain (localhost.localdomain [127.0.0.1])
by localhost.localdomain (8.13.8/8.13.8) with ESMTP id m979WDOf004744
for <[email protected]>; Tue, 7 Oct 2008 17:32:13 +0800
Received: (from [email protected])
by localhost.localdomain (8.13.8/8.13.8/Submit) id m979WCW3004743;
Tue, 7 Oct 2008 17:32:12 +0800
Date: Tue, 7 Oct 2008 17:32:12 +0800
Message-Id: <[email protected]>
From: [email protected] (Cron Daemon)
To: [email protected]
Subject: Cron <[email protected]> /backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;cat /tmp/gzgaCronLog.log|sendmail [email protected] "GZGA Backup Mission Finished!"
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/oracle>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=oracle>
X-Cron-Env: <USER=oracle>

/bin/sh: sendmail: command not found
請教上述錯誤資訊什麼原因?如何調整和修改才能實現我的預期功能1?
功能2:指令碼被CRON自動呼叫執行完成後向終端中傳送提示資訊:"XXXX年XX月XX日XX時XX分XX秒 GZGA Mission Finished Pls check ur mail",當前使用者沒有開啟終端就自動開啟一個終端傳送粗體提示資訊:"XXXX年XX月XX日XX時XX分XX秒 GZGA Mission Finished" ,提示資訊最好在終端的正中央! 
在不影響功能1的情況下具體如何修改ORACLE使用者的crontab語句才能實現功能2?
非常感謝!


------Solutions------
上述crontab語句執行過程中CentOS的sendmail服務正在執行
在/var/log/cron裡的內容:Oct  7 17:42:01 localhost crond[5200]: (oracle) CMD (/backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;cat /tmp/gzgaCronLog.log|sendmail [email protected] "GZGA Backup Mission Finished!")
Oct  7 17:44:01 localhost crond[5280]: (oracle) CMD (/backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;cat /tmp/gzgaCronLog.log|sendmail [email protected] "GZGA Backup Mission Finished!")
Oct  7 17:46:02 localhost crond[5358]: (oracle) CMD (/backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;cat /tmp/gzgaCronLog.log|sendmail [email protected] "GZGA Backup Mission Finished!")
Oct  7 17:48:01 localhost crond[5437]: (oracle) CMD (/backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;cat /tmp/gzgaCronLog.log|sendmail [email protected] "GZGA Backup Mission Finished!")

------Solutions------
XXXX年XX月XX日XX時XX分XX秒為oracle使用者的crontab語句執行完成後CentOS的當前時間。 
------Solutions------
用mail 試試!

------Solutions------
另外,用service sendmail status 看看sendmail服務是否啟動?

GOOD LUCK!

------Solutions------
to bshawk :非常感謝你的幫助!
用mail試過可以傳送,但我的sendmail一直是啟動狀態啊,是不是路徑的問題啊!
00-59/1 * * * * /backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;cat /tmp/gzgaCronLog.log|mail -s "GZGA backup finished!" [email protected]
用上述語句可以實現給[email protected]傳送標題為"GZGA backup finished!",內容為/tmp/gzgaCronLog.log中的內容!

我想實現的功能為:1.給[email protected]傳送標題為"XXXX年XX月XX日XX時XX分XX秒GZGA backup finished!",附件為/tmp/gzgaCronLog.log中最後一百行的內容!XXXX年XX月XX日XX時XX分XX秒為oracle使用者的crontab語句mail執行時CentOS的當前時間。
2:指令碼被CRON自動呼叫執行完成後向oracle終端中傳送提示資訊:"XXXX年XX月XX日XX時XX分XX秒 GZGA Mission Finished Pls check ur mail",當前使用者沒有開啟終端就自動開啟一個終端傳送粗體提示資訊:"XXXX年XX月XX日XX時XX分XX秒 GZGA Mission Finished" ,提示資訊最好在終端的正中央! 

請教具體如何修改上述crontab語句?

------Solutions------
up 
------Solutions------
up 
------Solutions------
oracle使用者 crontab -l如下: 
00-59/1 * * * * /backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;cat /tmp/gzgaCronLog.log|mutt -s "GZGA backup finished!" -a /tmp/gzgaCronLog.log [email protected] 

已實現每隔一分鐘向[email protected]發標題為"GZGA backup finished!"的郵件並附件功能!怎樣修改上述語句才能實現給[email protected]傳送標題為"XXXX年XX月XX日XX時XX分XX秒GZGA backup finished!",附件為/tmp/gzgaCronLog.log中最後一百行的內容!XXXX年XX月XX日XX時XX分XX秒為oracle使用者的crontab語句mutt執行時CentOS的當前時間。 
2:指令碼被CRON自動呼叫執行完成後向oracle終端中傳送提示資訊:"XXXX年XX月XX日XX時XX分XX秒 GZGA Mission Finished Pls check ur mail",當前使用者沒有開啟終端就自動開啟一個終端傳送粗體提示資訊:"XXXX年XX月XX日XX時XX分XX秒 GZGA Mission Finished" ,提示資訊最好在終端的正中央!

實現在不行拆分成兩個crontab語句也可以! 
------Solutions------
up 
------Solutions------
oracle使用者 crontab -l如下:
00-59/1 * * * * /backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;curdate=`date +%y%m%d`;cat /tmp/gzgaCronLog.log|mutt -s GZGABackupFinished${curdate} -a /tmp/gzgaCronLog.log 
 
/var/spool/mail/oracle:
From [email protected]  Sat Oct 11 15:49:02 2008 
Return-Path: <[email protected]
Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) 
by localhost.localdomain (8.13.8/8.13.8) with ESMTP id m9B7n1Eb018900 
for <[email protected]>; Sat, 11 Oct 2008 15:49:01 +0800 
Received: (from [email protected]
by localhost.localdomain (8.13.8/8.13.8/Submit) id m9B7n1L2018899; 
Sat, 11 Oct 2008 15:49:01 +0800 
Date: Sat, 11 Oct 2008 15:49:01 +0800 
Message-Id: <[email protected]
From: [email protected] (Cron Daemon) 
To: [email protected] 
Subject: Cron <[email protected]> /backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;curdate=`date + 
Content-Type: text/plain; charset=UTF-8 
Auto-Submitted: auto-generated 
X-Cron-Env: <SHELL=/bin/sh> 
X-Cron-Env: <HOME=/home/oracle> 
X-Cron-Env: <PATH=/usr/bin:/bin> 
X-Cron-Env: <LOGNAME=oracle> 
X-Cron-Env: <USER=oracle> 

/bin/sh: -c: line 0: unexpected EOF while looking for matching ``'
/bin/sh: -c: line 1: syntax error: unexpected end of file 



還是不行啊,錯誤資訊如上,請教如何解決? 
 
 

------Solutions------
oracle使用者 crontab -l如下: 
00-59/1 * * * * /backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;/mailme.sh 
/mailme.sh原始碼如下: 
curdate=`date +%y%m%d_%H%M%S`; 
tail -n 100 /tmp/gzgaCronLog.log > /tmp/gzgaCronLog.log.1; 
cat /tmp/gzgaCronLog.log.1 |mutt -s GZGABackupFinised${curdate} -a /tmp/gzgaCronLog.log.1 [email protected];wall "${curdate}GZGA Backup Mission Finised Pls check u guys' mail!!" 
************************************************************************************ 
上述語句已實現了:給[email protected]傳送標題為"XXXX年XX月XX日XX時XX分XX秒GZGA backup finished!", 附件為/tmp/gzgaCronLog.log中最後一百行的內容!XXXX年XX月XX日XX時XX分XX秒為oracle使用者的crontab語句mutt執行時CentOS的當前時間。 
2:指令碼被CRON自動呼叫執行完成後向當前所有已開啟終端中傳送提示資訊:"XXXX年XX月XX日XX時XX分XX秒 GZGA Mission Finished Pls check ur mail", 
現在的問題是: 
感覺mutt有時不能正常按設定的時間來發送郵件,有時能.而且怎麼設定能讓mutt支援中文?CentOS5.1的服務端在沒有終端開啟的情況下,wall "${curdate}GZGA Backup Mission Finised Pls check u guys' mail!!" 語句不能實現自動開啟一個終端並在其中持續顯示粗體"${curdate}GZGA Backup Mission Finised Pls check u guys' mail!!"  
------Solutions------
up 
------Solutions------
XP客戶機的虛擬機器內CentOS5.1下oracle使用者 crontab -l如下: 
00-59/1 * * * * /backupGZGA.sh 1>>/tmp/gzgaCronLog.log 2>>/tmp/gzgaCronLog.log;/mailme.sh 
***************************************************************************************** 
/mailme.sh原始碼如下: 
curdate=`date +%y%m%d_%H%M%S`; 
tail -n 100 /tmp/gzgaCronLog.log > /tmp/gzgaCronLog.log.1; 
cat /tmp/gzgaCronLog.log.1 |mutt -s GZGABackupFinised${curdate} -a /tmp/gzgaCronLog.log.1 [email protected];wall "${curdate}GZGA Backup Mission Finised Pls check u guys' mail!!" 
************************************************************************************ 
上述語句已實現了:每隔一分鐘執行指令碼backupGZGA.sh,給[email protected]傳送標題為"XXXX年XX月XX日XX時XX分XX秒GZGA backup finished!", 附件為/tmp/gzgaCronLog.log中最後一百行的內容的郵件!XXXX年XX月XX日XX時XX分XX秒為oracle使用者的crontab語句mutt執行時CentOS的當前時間。 
2:指令碼被CRON自動呼叫執行完成後向當前服務端所有已開啟終端中傳送提示資訊:"XXXX年XX月XX日XX時XX分XX秒 GZGA Mission Finished Pls check ur mail", 
現在的我欲實現的需求功能是: 
1.CentOS5.1的服務端在沒有終端開啟的情況下,實現自動開啟一個終端(黑色背景白色字型)並在其中持續顯示粗體資訊為:"${curdate}GZGA Backup Mission Finised Pls check u guys' mail!!" 
2.crontab語句中/mailme.sh執行後自動向已連線的和指定的Win XP客戶端(192.168.0.102/AFLRED01)傳送彈出式訊息內容為粗體"${curdate}GZGA Backup Mission Finised Pls check u guys' mail!!" 
Win XP客戶端包括以WINSCP或FLASHXP連線CentOS5.1的,我已下載了samba-3.2.4.tar.gz 到/usr/local下解壓完 
請教實現上述功能在我原有程式碼基礎上該如何修改crontab表語句及相關指令碼,用到xterm samba該如何切換使用者及配置?
或請高人提供詳細地更好的解決方案,非常感激! 
 
補充一下 功能1:如果CentOS5.1的服務端有已開啟的終端那就用wall "${curdate}GZGA Backup Mission Finised Pls check u guys' mail!!" 來發送提示資訊! 
 

------Solutions------
[root:/root]#crontab -l 
00-59/1 * * * * /testG.sh

根目錄下testG.sh 原始碼:
export DISPLAY=:0;
pid=`ps -e | grep -E 'gnome-terminal' | awk '{print $1}'`
echo "$pid";
if [ "$pid" != "" ] ; then
   gnome-terminal &

fi
**************************************************************************************
上述crontab語句和shell指令碼總是每隔一分鐘就通過gnome-terminal彈出一個可互動式終端(由gnome-terminal命令開啟並可接受wall廣播資訊),怎樣通過修改上述程式碼實現:服務端沒有終端開啟時開啟一個可互動式終端並保證其不自動關閉,當已有一個可互動式終端存在時就不再重複開啟新的可互動式終端.
謝謝! 
------Solutions------
up 
------Solutions------
請教CentS5.1下,在SMB服務啟動的情況下,如何用smbclient命令向已連線服務端的以及指定的windows客戶端傳送彈出式提示訊息?具體如何配置SMB服務?