-
前段时间自己租用了一个ubuntu系统的云服务器,想要配置一个自动利用电子邮件发送信息的脚本,但是由于本人水平实在有点不堪入目,配置mailx失败了,所以利用有限的python
知识,写了一个邮件客户端。由于目的就是在命令行界面使用(毕竟图形界面的邮件客户端好用的太多了),没有做UI界面(水平也不允许),目前能够实现命令行发送带有附件或者没有附件的邮件,可以命令行查看收件箱,可以下载并查看指定的邮件及附件。
代码有点乱,毕竟业余菜鸟水平,如果有人看到这个程序并想要提供宝贵的想法或意见,欢迎联系留言,或者到项目地址贡献您的宝贵意见(https://gitee.com/imechy/dumail)
安装教程 项目地址:https://gitee.com/imechy/dumail 目前ubuntu 22 /24可以运行
下载dumail.py,修改为可运行权限
下载dumail.rc到“/etc”下(建议)或者home文件夹或者运行dumail.py的文件夹,或者放在任何你想放的位置,但是在主文件里创建Mail()类的时候,dumail.rc的详细路径需要作为参数传入。
在dumail.rc 里面根据自己情况设置参数
使用了第三方库bs4,需要自行安装pip install bs4或者sudo apt install python3-bs4
阅读html的邮件内容用到了w3m(命令行网页浏览器),需要提前安装好sudo apt install w3m使用说明
-
目前实现能够发送多个附件,或者文本邮件
-
能查看收件箱信息列表,在命令行界面查看html的邮件只能查看文字内容和下载附件,美观就不能提了,后面尽量优化(遥遥无期)
-
目前收信功能因为某易邮箱的IMAP协议需要认证客户端,所以用的POP3协议,发信用的SMTP
-
主体是一个mail()类 方法: .from_cmd(self) 对于命令行的支持主要在这个方法里面实现: -c --Content
:添加邮件文本内容(字符串)或者包含内容的文件路径(字符串) -s --Subject :邮件主题(字符串) -f --From
:邮件的from 字段的内容,发送人 -t --To :收件人,可以是单个邮箱地址(字符串)也可以是多个邮箱地址列表(字符串列表)-t
reciever1 [reciever2] …-a --Attachments:邮件附件路径,-a path1 [path2] [path3]… -l --List :邮件列表,默认每次显示8条邮件 ,-l /num可以将每次显示的邮件数量修改为num -r --read :阅读由参数指定的邮件,-r
index 阅读编号为index 的邮件 -d --delete :删除本地和服务器端指定编号的邮件 ,-d index1
[index2] [index3]… -
.send_mail(self,From=‘’,To=‘’,Content=‘’,Subject=‘’,Attachments1=[],**Attachments2)
发送邮件 Attachments1:邮件附件的路径列表,或者单个文件路径 *Attachments2:需要发送二进制文件时 ,使用
filename1=Bytes1,filename2=Bytes2,…的形式 .list_msg(self,flags=‘’)
显示邮件列表 flag:根据邮件标志位筛选邮件 N:new msg U:unread msg D:writing F:marked
P:retrieve R:replied S:seen T:deleted L:new load -
.read(self,index_r) 阅读邮件 index_r:邮件编号,如果编号不存在会显示编号错误
.del_msg(self,index) 删除服务器和本地的编号为index 的邮件 -
文件代码在最后(有好多冗余和没什么用的代码,但是基于能跑就行的原则,目前先这样吧)如果有人愿意试用,欢迎把遇到的bug、异常反馈给我,非常感谢!
#!/usr/bin/python3
import email.parser
from smtplib import SMTP_SSL
from poplib import POP3_SSL
from poplib import error_proto
from email.message import EmailMessage
import email
import configparser
import os
import argparse
import base64
import mailbox
import time
from email.iterators import _structure
from bs4 import BeautifulSoup
import subprocess
#import quopri
class Mail(object):
def __init__(self,profile_path='/etc/dumail.rc'):
self.profile_path=''
self.config=configparser.ConfigParser()
self.args=argparse.Namespace()
self.user=''
self.password=''
self.From=''
self.To=''
self.smtp_server=''
self.smtp_port=0
self.imap_server=''
self.imap_port=0
self.pop3_server=''
self.pop3_port=0
self.mail_box=''
self.msg=EmailMessage()
self.new_msg_index=[]
self._msg_per_page=8
try:
self.mail_box=mailbox.Maildir(os.path.expanduser('~/.Mail'))
os.mkdir(os.path.expanduser('~/.Mail/Attachments'))
except Exception as err:
print('Creat mailbox dir ~/mail error:', err)
self.cmd_args=False
self.load_config(profile_path)
def load_config(self,path):
try:
if os.path.isfile(path) and os.path.exists(path):
self.config.read(path)
elif os.path.exists('./dumail.rc'):
self.config.read('./dumail.rc')
elif os.path.exists(os.path.expanduser('~/.dumail.rc')):
self.config.read(os.path.expanduser('~/.dumail.rc'))
elif os.path.exists(os.path.expanduser('~/.Mail/.dumail.rc')):
self.config.read(os.path.expanduser('~/.Mail/.dumail.rc'))
else:
print("Do not find 'dumail.rc' in '/etc' or './/' or '.dumail.rc' in ~/ ")
print('you can use cmd args to difine server and send email')
except Exception as err:
print(err.with_traceback())
exit()
if self.config.has_option('DEFAULT','user') and self.config.has_option('DEFAULT','user') !='':
self.user=self.config.get('DEFAULT','user')
else:
print('there is not a user in dumail.rc')
if self.config.has_option('DEFAULT','password') and self.config.has_option('DEFAULT','password') !='':
self.password=self.config.get('DEFAULT','password')
else:
print('there is not a password in dumail.rc')
if self.config.has_option('SMTP_SERVER','addr') and self.config.has_option('SMTP_SERVER','port') and self.config.has_option('SMTP_SERVER','addr')!='' and self.config.has_option('SMTP_SERVER','port')!='':
self.smtp_server=self.config.get('SMTP_SERVER','addr')
self.smtp_port=self.config.get('SMTP_SERVER','port')
else:
print('there is not a smtp server in dumail.rc')
if self.config.has_option('IMAP_SERVER','addr') and self.config.has_option('IMAP_SERVER','port') and self.config.has_option('IMAP_SERVER','addr')!='' and self.config.has_option('IMAP_SERVER','port') !='':
self.imap_server=self.config.get('IMAP_SERVER','addr')
self.imap_port=self.config.get('IMAP_SERVER','port')
else:
print('there is not a IMAP server in dumail.rc')
if self.config.has_option('POP3_SERVER','addr') and self.config.has_option('POP3_SERVER','port') and self.config.has_option('POP3_SERVER','addr')!='' and self.config.has_option('POP3_SERVER','port') !='':
self.pop3_server=self.config.get('POP3_SERVER','addr')
self.pop3_port=self.config.get('POP3_SERVER','port')
else:
print('there is not a pop3 server in dumail.rc')
def from_cmd(self):
self.cmd_args=True
parser=argparse.ArgumentParser(description='send email and with attachments')
parser.add_argument('-c','--Content',type=str,help='the content of the email,str or file path')
parser.add_argument('-s','--Subject',type=str,help='the subject of the email')
parser.add_argument('-f','--From',type=str,help='the sender of the email')
parser.add_argument('-t','--To',type=str,nargs='*',help='the reciever of the email;required')
parser.add_argument('-a','--Attachments',type=str,nargs='*',help='the attachments of the email[path1 path2 ...]')
parser.add_argument('-l','--List',type=str,nargs='*',help='the num of msg you want list once ; newer first')
parser.add_argument('--find',type=str,help='--find index or keywords in From/date/subject')
parser.add_argument('-r','--read',type=str,nargs='+',help='read a msg by index ,at least one argument')
parser.add_argument('-d','--delete',type=str,nargs='*',help='delete msg in local mailbox and server')
self.args=parser.parse_args()
if self.args.delete!=None:
self.del_msg(self.args.delete)
if self.args.To!=None:
self.send_mail(From=self.args.From,To=self.args.To,Content=self.args.Content,Subject=self.args.Subject,Attachments1=self.args.Attachments)
if self.args.List!=None:
if len(self.args.List)<=0: # N:new msg
self.list_msg() # P:retrieve
else :
flag_s='' # U:unread msg
for item in self.args.List: # R:replied
if '+' in item: # F:marked
flag_s=item.replace('+','') # S:seen
#print(flag_s)
elif '/' in item : # D:writing
if item.replace('/','').isdecimal(): # T:deleted
self._msg_per_page=int(item.replace('/','')) # L:new load*
else:
print('Wrong arguments after "-l /"!')
else :
flag_s=''
#print('flag_s')
self.list_msg(flags=flag_s)
if self.args.read!=None:
if self.args.read[0].isdecimal():
self.read(self.args.read[0])
def send_mail(self,From='',To='',Content='',Subject='',Attachments1=[],**Attachments2):
'''
From : the email sender
To : the email reciever
Subject : subject
Attachments1 : should be a path list of files to send
Attchments2 : should be filename1(str)=filedate1(bytes),filename2(str)=filedate2(bytes),...
'''
with SMTP_SSL(self.smtp_server,self.smtp_port) as smtp:
if self.cmd_args:
if len(self.args.To) > 0 :
self.msg['To']=','.join(self.args.To)
self.To=self.args.To
elif self.config.has_option('DEFAULT_SETTINGS','reciever'):
self.msg['To']=self.config.get('DEFAULT_SETTINGS','reciever')
self.To=self.config.get('DEFAULT_SETTINGS','reciever').split(',')
print('email will send to the default reciever:',self.To)
else:
print('please input a email address')
if self.args.Content == None:
self.msg.set_content('')
elif os.path.isfile(self.args.Content) :
with open(self.args.Content) as fp:
self.msg.set_content(fp.read())
else:
self.msg.set_content(self.args.Content )
if self.args.Subject != None:
self.msg['Subject']=self.args.Subject
elif self.config.has_option('DEFAULT_SETTINGS','subject'):
self.msg['Subject']=self.config.get('DEFAULT_SETTINGS','subject')
else:
self.msg['Subject']=''
if self.args.From != None:
self.msg['From']=self.args.From
self.From=self.args.From
elif self.config.has_option('DEFAULT_SETTINGS','from'):
self.msg['From']=self.config.get('DEFAULT_SETTINGS','from')
self.From=self.config.get('DEFAULT_SETTINGS','from')
else:
self.msg['From']=self.config.get('DEFAULT','user')
self.From=self.config.get('DEFAULT','user')
if self.args.Attachments !=None:
for attach in self.args.Attachments:
if os.path.isfile(attach):
with open(attach,'rb') as ap:
af=ap.read()
self.msg.add_attachment(af,maintype='application',subtype='octet-stream',filename=ap.name.split('/')[-1])
print('add attach:',attach)
else:
self.msg.set_content(Content)
self.msg['Subject']=Subject
self.msg['From']=From
self.msg['To']=To
self.To=To.split(',')
self.From=From
if len(Attachments1)>0:
for attach in Attachments1:
if os.path.isfile(attach):
with open(attach,'rb') as at:
self.msg.add_attachment(at.read(),maintype='application',subtype='octet-stream',filename=at.name.split('/')[-1])
#print('add attach:',attach)
if len(Attachments2)>0:
for key in Attachments2:
self.msg.add_attachment(Attachments2[key],maintype='application',subtype='octet-stream',filename=key)
smtp.login(self.user,self.password)
for to in self.To:
smtp.send_message(self.msg,self.From,to)
def get_mail(self,index=0,top_only=True):
try:
pop3 = POP3_SSL(self.pop3_server,self.pop3_port)
except Exception as err:
print('Connect error in get_mail():',err)
else:
try:
serv_res=pop3.user(self.user)
mail_info=pop3.pass_(self.password)
except error_proto as err:
print('user or password invalid:',err)
else:
if not top_only:
res,msg_all_bytes_list,oct=pop3.retr(int(index))
res=True
if res:
msg_all_bytes=b''
for item in msg_all_bytes_list:
msg_all_bytes += (item+b'\n')
msg_all_tmp=mailbox.MaildirMessage(email.message_from_bytes(msg_all_bytes))
msg_old = self.mail_box.get(self._msg_get_key(index))
msg_all_tmp.set_info(msg_old.get_info())
msg_all_tmp=self._msg_set_info(msg_all_tmp,inf='ALL')
self.mail_box.__setitem__(self._msg_get_key(index),msg_all_tmp)
else:
print(mail_info)
if int(mail_info.decode().split()[1])<1:
print('mailbox on server is empty!')
exit()
try:
mail_list=pop3.list()[1]
except Exception as err:
print('get mail list error',err)
exit()
else:
for msg_info in mail_list:
try:
msg_index=msg_info.decode().split()[0]
msg_top_bytes_list=pop3.top(msg_index,0)[1]
except Exception as err:
print('decode or get msg top error',err)
exit()
else:
msg_top_bytes=b''
for item in msg_top_bytes_list:
msg_top_bytes += (item+b'\n')
msg_tmp=mailbox.MaildirMessage(email.message_from_bytes(msg_top_bytes))
if not self._msg_exist(msg_tmp,index=msg_index):
Key=self.mail_box.add(msg_tmp)
msg_tmp=self._msg_set_info(msg_tmp,index=msg_info.decode().split()[0],flag='+UL',inf='TOP',size=msg_info.decode().split()[1],key=Key)
self.mail_box.__setitem__(Key,msg_tmp)
self.new_msg_index.append(Key)
'''
N:new msg
U:unread msg
D:writing
F:marked
P:retrieve
R:replied
S:seen
T:deleted
L:new load*
'''
print('load mail done!')
pop3.quit()
def _show_info(self):
n=0
u=0
f=0
s=0
l=0
for key in self.mail_box.keys():
msg=self.mail_box.get(key)
info_list=msg.get_info().split()
if 'N' in info_list[1]:
n=n+1
if 'U' in info_list[1]:
u=u+1
if 'F' in info_list[1]:
f=f+1
if 'S' in info_list[1]:
s=s+1
if 'L' in info_list[1]:
l=l+1
#print('info:',msg.get_info())
print('Time:',time.asctime())
print('New load:',l)
print('New message:',n)
print('Unread:',u)
print('Seen:',s)
print('Marked',f)
def _msg_set_info(self,msg=mailbox.MaildirMessage(),index='',flag='',inf='',size='',key=''):
'''
msg:mailbox.MaildirMessage()
index:index on server
falg:
inf:top only or all
size:msg size
key:mailbox.key
'''
if msg.get_info()=='':
info_list=[index,flag,inf,size,key]
msg.set_info(' '.join(info_list))
return msg
else:
info_list=['','','','','']
tmp_list=msg.get_info().split()
if len(info_list)<=len(tmp_list):
info_list=tmp_list
for i in range(len(tmp_list)):
info_list[i]=tmp_list[i]
if index !='':
info_list[0]=index
if flag !='':
info_list[1]=flag
if inf !='':
info_list[2]=inf
if size !='':
info_list[3]=size
if key !='':
info_list[4]=key
msg.set_info(' '.join(info_list))
return msg
def _remove_flags(self,msg=mailbox.MaildirMessage(),flags=''):
if type(msg)==type(' '):
info=self.mail_box.get(msg).get_info()
elif type(msg)==type(mailbox.MaildirMessage()):
info_list=msg.get_info().split()
flag_str=info_list[1]
for flag in flags:
if flag.upper() in flag_str:
flag_str=flag_str.replace(flag.upper(),'')
info_list[1]=flag_str
else:
#print('{} flag dot exist'.format(flag))
pass
msg.set_info(' '.join(info_list))
self.mail_box.__setitem__(self._msg_get_key(msg),msg)
return msg
def _msg_get_key(self,msg):
''' get a argument as str/int of index or mailbox.MaildirMessage()\
return :mailbox.key(str)
'''
if type(msg)==type(mailbox.MaildirMessage()):
return msg.get_info().split()[-1]
elif type(msg)==type(str()) or type(msg)==type(int()):
for key in self.mail_box.keys():
info=self.mail_box.get(key).get_info()
if str(msg)==info.split()[0]:
return info.split()[-1]
def _add_flags(self,msg=mailbox.MaildirMessage(),flags=''):
if type(msg)==type(' '):
info=self.mail_box.get(msg).get_info()
elif type(msg)==type(mailbox.MaildirMessage()):
info=msg.get_info()
info_list=info.split()
flags_str=info_list[1]
if flags!='':
flags_list=list(flags)
for flag in flags_list:
if flag.upper() not in flags_str:
flags_str=flags_str+flag.upper()
info_list[1]=flags_str
msg.set_info(' '.join(info_list))
self.mail_box.__setitem__(self._msg_get_key(msg),msg)
return msg
else:
return msg
def _msg_exist(self,msg,index=''):
for key in self.mail_box.keys():
msg_tmp=self.mail_box.get(key)
if msg['Message-ID']==msg_tmp['Message-ID']:
if msg_tmp.get_info().split()[0]!=str(index):
#print('index dont eq')
self.mail_box.discard(self._msg_get_key(index))
self.mail_box.flush()
msg_tmp=self._msg_set_info(msg_tmp,index=index)
msg_tmp=self._remove_flags(msg_tmp,'L')
self.mail_box.__setitem__(key,msg_tmp)
return True
else:
return False
def _decode_base64_str(self,str_to_decode):
while (str_to_decode.find('=?UTF-8?B?'))>=0 and (str_to_decode.find('?='))>=0:
#print('there are base64 code')
try:
str_to_decode=(str_to_decode[0:(str_to_decode.find('=?UTF-8?B?'))]+base64.decodebytes(str_to_decode[(str_to_decode.find('=?UTF-8?B?')+len('=?UTF-8?B?')):(str_to_decode.find('?='))].encode()).decode()+str_to_decode[(str_to_decode.find('?='))+len('?='):])
#print(str_to_decode)
except Exception as err:
print('base64 decode error:',err)
return str_to_decode
#print('base64 decoded')
else:
#print('not find base64')
return str_to_decode
pass
def _msg_print(self,str_to_decode):
print(self._decode_base64_str(str_to_decode))
def list_msg(self,flags=''):
self.get_mail()
self._show_info()
print('Index Flag Date From Subject')
key_dict={}
for key in self.mail_box.keys():
# msg=self.mail_box.get(key)
info=self.mail_box.get(key).get_info()
# index=int(info.split()[0])
if flags.replace('+','') !='':
for flag in flags.upper():
if flag in info.split()[1]:
#print(flag,info.split()[1])
index_int=int(info.split()[0])
key_dict[index_int]=key
else:
index_int=int(info.split()[0])
key_dict[index_int]=key
#print(key_dict)
index_sorted=sorted(key_dict,reverse=True)
count=0
for index in index_sorted:
msg=self.mail_box.get(key_dict[index])
info_list=msg.get_info().split()
print('{0:<5} {1:<6}{2:<10} {3:<45} {4:<30}'.format(info_list[0],info_list[1],msg['Date'][0:25],self._decode_base64_str(msg['From']),self._decode_Subject(msg['Subject'])))
count=count+1
if count>=self._msg_per_page or index==index_sorted[-1]:
count=0
i =input('press "enter" to continue or press "q enter" to stop or input the index to read:')
if i.isdecimal() and (int(i)<=index_sorted[0]) and (int(i)>=index_sorted[-1]) :
self.read(int(i))
i=input('press "enter" to continue or press "q enter" to stop :')
if i=='q':
break
continue
elif i=='q':
break
elif index!=index_sorted[-1]:
for i in range(self._msg_per_page+2):
print('\33[1A',end='')
print('\033[K',end='')
#print('\033[2J')
def _decode_Subject(self,subject_str=''):
if '\n' in subject_str:
subject_str=subject_str.replace('\n','')
return self._decode_base64_str(subject_str)
def read(self,index_r):
for key in self.mail_box.keys():
msg_tmp=self.mail_box.get(key)
info=msg_tmp.get_info()
if str(index_r) == info.split()[0]:
self._remove_flags(msg_tmp,'LNU')
self._add_flags(msg_tmp,'S')
if 'ALL' in info:
self.show_msg(index_r)
break
elif 'TOP' in info:
self.get_mail(top_only=False,index=index_r)
self.show_msg(index_r)
break
else:
self.get_mail(index_r,top_only=False)
self.show_msg(index_r)
break
else:
print('wrong msg index!')
def show_msg(self,index):
key=self._msg_get_key(index)
msg_to_show=self.mail_box.get(key)
print('info:',msg_to_show.get_info())
print('From:',self._decode_base64_str(msg_to_show['From']))
print('To:',msg_to_show['To'])
print('Subject:',self._decode_Subject(msg_to_show['Subject']))
print()
#print('Content:')
self.parse_msg(msg_to_show)
def parse_msg(self,msg):
if msg.get_content_maintype()=='text':
if msg.get_content_subtype=="plain":
print(msg.get_payload(decode=True))
pass
elif msg.get_content_subtype()=='html':
msg_content=BeautifulSoup(msg.get_payload(decode=True),'html.parser')
with open(os.path.expanduser('~/.Mail/tmp.html'),'+a') as tmp:
tmp.write(str(msg_content))
subprocess.run(['w3m',os.path.expanduser('~/.Mail/tmp.html')])
os.remove(os.path.expanduser('~/.Mail/tmp.html'))
#print(msg_content.getText().replace('\n',''))
#print()
pass
if msg.get_content_disposition()=='attachment':
print('Attachment:',msg.get_filename())
print('ContentType:',msg.get_content_type())
print('Transfer-encoding:',msg.get("Content-Transfer-Encoding"))
#print('Size:{} Bytes'.format(msg.get_all('size')))
print('Saved : ~/.Mail/Attachments/{}'.format(msg.get_filename()))
print()
with open(os.path.expanduser('~/.Mail/Attachments/{}'.format(msg.get_filename())),'+bw') as at:
at.write(msg.get_payload(decode=True))
if msg.is_multipart():
for part in msg.get_payload():
self.parse_msg(part)
def parse_msg_body(self,msg):
str_buf=''
if msg.get_content_maintype()=='text':
if msg.get_content_subtype=="plain":
str_buf=str_buf+(msg.get_payload(decode=True))
pass
elif msg.get_content_subtype()=='html':
msg_content=BeautifulSoup(msg.get_payload(decode=True),'html.parser')
str_buf+=(msg_content.getText().replace('\n',''))
#print()
if msg.is_multipart():
for part in msg.get_payload():
str_buf+=self.parse_msg_body(part)
return str_buf
def del_msg(self,index):
try:
pop3 = POP3_SSL(self.pop3_server,self.pop3_port)
except Exception as err:
print('Connect error:',err)
else:
try:
serv_res=pop3.user(self.user)
mail_info=pop3.pass_(self.password)
except error_proto as err:
print('user or password invalid:',err)
else:
if type(index)==type(str()) or type(index)==type(int()):
pop3.dele(str(index))
pop3.quit()
self.mail_box.discard(self._msg_get_key(index))
self.mail_box.flush()
if type(index)==type(list()):
for item in index:
pop3.dele(str(item))
self.mail_box.discard(self._msg_get_key(str(item)))
pop3.quit()
self.mail_box.flush()
def output_log(self,info):
try :
with open(os.path.expanduser('~/.Mail/.mail.log'),'+ab') as log_file:
log_file.writelines('TIME : '+time.asctime()+' \n')
log_file.writelines('INFO : '+info+'\n')
except Exception as err:
print('Log failed!',err)
def get_msg(self,index):
msg_list=[]
for key in self.mail_box.keys():
msg_tmp=self.mail_box.get(key)
info=msg_tmp.get_info()
if str(index) == info.split()[0]:
break
self.msg['From']=msg_tmp['From']
self.msg['Subject']=self._decode_Subject(msg_tmp['Subject'])
# self.msg.set_content(self.parse_msg_body(msg_tmp))
# print(base64.b64decode(self.msg.get_payload()))
return (self.msg)
if __name__=="__main__":
mail=Mail(os.path.expanduser('~/Documents/dumail.rc'))#这里是我自己的rc文件位置,需要根据自己的情况填写
mail.from_cmd()
```
```python
下面是dumail.rc
[DEFAULT]
#邮箱账户,str类型,注意不要有引号
user=xxxxxx@xxx.com
#邮箱密码,或者大部分邮箱会要求使用授权码str类型,注意不要有引号
password=xxxxxxxxxxxxxx
#提供smtp服务的服务器信息
[SMTP_SERVER]
#smtp服务器地址
addr=smtp.xxx.com
#smtp服务端口,ssl为465,具体需要查看邮箱网站
port=465
#提供imap服务的服务器信息(本文没用到)
[IMAP_SERVER]
#imap服务器地址
addr=imap.xxx.com
#imap服务端口,ssl为993,具体需要查看邮箱网站
port=993
#pop3 server 本文用的pop3协议,这个要填写
[POP3_SERVER]
addr=pop3.xxx.com
port=995
#一些默认设置,可选
[DEFAULT_SETTINGS]
#默认收件人
reciever=xxxxxx@xxx.com
#指定发件人
from=xxxxxxx@xxx.com