【Python系列】Python自動發郵件腳本-html郵件內容

緣起

這段時間給朋友搞了個羣發郵件的腳本,爲了防止進入垃圾郵件,作了不少工做,剛搞完,垃圾郵件進入率50%,以爲還不錯,若是要將垃圾郵件的進入率再調低,估計就要花錢買主機了,想一想也就算了,先發一個月,看看效果再拓展吧。html

腳本主要是經過Python寫的,調的smtplib庫,這些是基礎,你們在網上一搜一大堆,今天主要給你們講解下如何避免進入垃圾郵件系統,以及整個系統搭建時的一些思想。可能剛搞Python不久,有不少多是錯誤的寫法望你們提出來哈~python

配置

CentOS7.0系統c++

Python 3.4git

CentOS7.0下面默認的是Python2.7.5,咱們先來將Python的版本提高上去vim

#wget https://www.python.org/ftp/python/3.4.3/Python-3.4.3.tgz

下載Python3.4版本數組

#tar -xf Python-3.4.3.tgz
#cd Python-3.4.3/
#./configure

這邊configure的時候可能會遇到你的環境沒有安裝gcc編譯環境,執行下面的語句再configure便可安全

#yum -y install gcc
#yum -y install gdb
#yum -y install gcc-c++

編譯安裝服務器

#make
#make install

由於替換了python版本以後yum可能不能正常使用,需改兩個文件架構

#vim /usr/bin/yum
#vim /usr/libexec/urlgrabber-ext-down

將這兩個文件的頭部的#!/usr/bin/python改爲#!/usr/bin/python2.7便可,保存退出,yum滿狀態復活app

編譯完了以後,將python3.4設置爲默認python解析。

#ln -s /usr/local/bin/python3.4 /usr/bin/python

連接完成以後檢查python版本

#python -V

出現Python3.4就標識版本切換完成

系統架構

Account:用於存放發送者郵箱帳號的目錄,個人163郵箱,sina郵箱,sohu郵箱和tom郵箱均在淘寶上購買了30個能夠發送smtp服務的帳號,花費一頓飯的錢不到就能夠搞到啦~帳號密碼用【:】分割,每一個帳號之間使用【,】分割。

Common:引用類文件夾,裏面是日至系統配置文件和日誌系統源代碼

Conf:全局配置文件,目前還木有用到

Image:郵件發送過程當中須要使用到的圖片資源

Log:日誌文件,按日期區分

Logbackups:日誌備份文件,用於備份過時日誌

Sendmail:用於存儲收件人的郵箱信息,帳號之間用【,】分割

mail_html.py:主要執行腳本

README.md:git版本控制用戶須知,我是經過碼雲來管理個人代碼的

日誌系統

提起腳本系統,日誌是至關關鍵的一個角色,尤爲是當你的腳本出錯,你要查錯的時候,就很是重要了,我也是從網上搞來的一段Log日誌系統的代碼,以爲挺好用,供大夥參考~

主要思想是,打印log到指定文件,打印log到屏幕,啥也不說了,先上代碼,由於是網上的代碼,我就放上來啦~

# coding: utf-8

#from lxml import etree
import logging.handlers
import logging
import os
import sys
import time
import datetime

try: 
  import xml.etree.cElementTree as ET 
except ImportError: 
  import xml.etree.ElementTree as ET 

# 提供日誌功能
class logger:
    # 先讀取XML文件中的配置數據
    # 因爲config.xml放置在與當前文件相同的目錄下,所以經過 __file__ 來獲取XML文件的目錄,而後再拼接成絕對路徑
    # 這裏利用了lxml庫來解析XML
    root = ET.parse(os.path.join(os.path.dirname(__file__), 'config.xml')).getroot()
    # 讀取日誌文件保存路徑
    logpath = root.find('logpath').text
    # 讀取日誌文件容量,轉換爲字節
    logsize = 1024*1024*int(root.find('logsize').text)
    # 讀取日誌文件保存個數
    lognum = int(root.find('lognum').text)
    
    # 添加分天日誌名
    now = datetime.datetime.now()
    now_time = now.strftime('%Y%m%d')
    log_file_name = sys.argv[0].split('/')[-1].split('.')[0] + '_' + now_time
    # 日誌文件名:由用例腳本的名稱,結合日誌保存路徑,獲得日誌文件的絕對路徑
    logname = os.path.join(logpath, log_file_name)

    # 初始化logger
    log = logging.getLogger()
    # 日誌格式,能夠根據須要設置
    fmt = logging.Formatter('[%(asctime)s][%(filename)s][line:%(lineno)d][%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')

    # 日誌輸出到文件,這裏用到了上面獲取的日誌名稱,大小,保存個數
    handle1 = logging.handlers.RotatingFileHandler(logname, maxBytes=logsize, backupCount=lognum)
    handle1.setFormatter(fmt)
    # 同時輸出到屏幕,便於實施觀察
    handle2 = logging.StreamHandler(stream=sys.stdout)
    handle2.setFormatter(fmt)
    log.addHandler(handle1)
    log.addHandler(handle2)

    # 設置日誌基本,這裏設置爲INFO,表示只有INFO級別及以上的會打印
    log.setLevel(logging.INFO)

    # 日誌接口,用戶只需調用這裏的接口便可,這裏只定位了INFO, WARNING, ERROR三個級別的日誌,可根據須要定義更多接口
    @classmethod
    def info(cls, msg):
        cls.log.info(msg)
        return

    @classmethod
    def warning(cls, msg):
        cls.log.warning(msg)
        return

    @classmethod
    def error(cls, msg):
        cls.log.error(msg)
        return

日誌系統的配置文件

<?xml version="1.0" encoding="utf-8"?>

<config>
    <!--  日誌保存路徑  -->
    <logpath>/Users/litao/Desktop/mail_html/Log</logpath>

    <!-- 每一個腳本對應的日誌文件大小,單位MB -->
    <logsize>8</logsize>

    <!-- 每一個腳本保存的日誌文件個數 -->
    <lognum>100</lognum>
</config>

保存的路徑各位隨意哈。

如何使用

logger.info('郵件總數量【'+str(len(recivers))+'')                                                                                          
logger.info('總計發送郵件數量【'+str(send_num)+'')                                                                                         
logger.info('總計發送錯誤數量【'+str(error_num)+'')                                                                                        
logger.info('成功郵箱帳號集合:'+','.join(send_success_account))                                                                             
logger.info('失敗郵箱帳號集合:'+','.join(send_failure_account))                                                                             
logger.info('腳本結束------------------------------------------------------------------')                                                    
logger.info('')                                                                        

error的話將info換成error便可

執行主文件

提起垃圾郵件,你們首先想到的就是那個使人討厭的垃圾箱裏面的營銷郵件,可是,若是你的郵件內容寫的很棒,是否是就能夠避免被封殺,答案是否認的,郵件被封殺是機器乾的,若是是機器乾的事,那就好辦了,首先,咱們得先知道機器的工做原理。

大部分被列爲垃圾郵件的郵件均有兩個特徵:內容不變,IP不變,其實作到內容一直變,IP一直變理論上就能夠作到不進垃圾郵箱,可是哪有那麼多的人力物力作這事,因此,咱們要作的是解決機率性的問題。

內容混淆

內容不變咱們可使用多套模板,嵌套着發,這個問題好解決,可是IP不變,這個就難一點了,其實我也沒解決,主要是怕花錢,我能作的就是經過多套模板來實現內容機率性的不被封殺。

好了,咱們先準備30個郵件的subject,30套郵件的內容模板,下面就是個人全局subject配置

這樣作的好處就是能夠防止郵件的內容被封殺,假設咱們30秒發一封郵件,那麼在20分鐘內的郵件,沒有一封是重複的。咱們是從接受郵箱域名的角度考慮的,也就是若是咱們的營銷對象全是QQ郵箱,那麼QQ郵箱的郵箱服務器在20分鐘內收到同一IP的郵件內容是不同的,這很大程度上就能避免被封殺。

帳戶混淆

設置這麼多帳號是幹嗎用的呢,主要仍是想混淆機器,讓垃圾郵件進率更低。

下面我我的通過測試,發現郵箱服務器具備的一些特性。

163郵箱

163郵箱設置了天天每一個帳號郵件發送的上限位50封,帳號554出錯重發的時間是3小時。

tom郵箱

tom郵箱天天郵件發送數量不作限制,咱們也假設是50封,可是每封郵件之間的發送間隔必定要超過30秒,要否則會被短期鏈接數過大報錯。

sohu郵箱

業界良心,基本上沒出過啥錯誤,一直保持着良好的發送成功率。咱們也將其定位發送間隔30秒,每日上線50封。

sina郵箱

噁心的玩意兒,每次發送郵箱前須要先登陸,認證手機號,每一個手機號5個郵箱哈,可是效果顯著,認證完畢,和sohu同樣,基本沒出錯過。

時間混淆

有了這些基礎,咱們就能夠知道了,咱們有120個帳號,30個郵件模板,天天一刻不停的發送,每封郵件之間的間隔爲30秒,一天的郵件發送量在2800封左右。

我以爲一天2800封,若是有錢的話,一臺ESC的費用是3元天天,獨立ip哈,若是找第三方發送,一封郵件是3分錢,量大2分錢,他們是EDM的,我測試過1500封,達到率不足千分之一。也就是說,咱們發送1500封,只須要1塊多錢,找第三方發送,1500封怎麼也得40塊錢。成本是否是很低。

好的,那就來看看郵件是如何發送的吧。

郵件發送

下面咱們來看下個人主文件是如何搞的

#coding=utf-8
import smtplib
import mimetypes
import time
import datetime

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage

#引入外部文件
from Common.log import *

導入模塊,以來的外部庫和內部的文件

#目錄主位置
_root_dir = '/Users/litao/Desktop/mail_html/'
_title_common = '愚人節'

愚人節主題禮物,也是爲了之後省事,subject和內容中設計到title的均會被改成愚人節,立刻愚人節了嗎,營銷方式,代碼實現,異常方便修改。

#郵箱內容設置
_content = """\
<html>
    <style> .title{font-weight:bold;font-size:18px;}</style>
    <body>
        <p>
            <img src="cid:image1">
            <br><br>
            <span
            class="title">【愚人節】將至,您還沒準備禮物?那你必定會過個開心的愚人節的</span>
            <br>
            愚人節就要來啦,禮朵朵給大夥準備了大批量的禮物伴你度過愚人節,具體百度一下【禮朵朵】,趕忙進站選禮物吧~
            <br>
            選禮物前別忘了先去心願牆許願喲,你的願望可能被禮朵朵看到,能夠幫你實現喲,實現的時候別忘了來禮朵朵還願哈~
            <br><br>
            <span class="title">【禮朵朵】介紹</span>
            <br>
            國人從古至今都有送禮的習俗,送禮做爲傳統之一,一直流傳至今,禮尚往來成爲人生必修課。
            <br>
            【禮朵朵】集合商業送禮和現代送禮搭建禮物導購分享平臺【朵朵禮物】,帶給老小皆宜的送禮分享體驗新體驗。
            <br>
            與此同時,禮朵朵還給大夥準備了禮物攻略【禮物說】,讓你們能夠對禮物有個更全面的瞭解~
            <br><br>
            <span class="title">百度搜索【禮朵朵】,開啓你的禮物新旅程吧~</span>
            <br><br>
        </p>
    </body>
</html> 
""" 

營銷內容模板,html模式實現郵件的發送,少不了有模板~

#發送郵箱smtp地址
_smtp_address = ['smtp.163.com','smtp.sina.cn','smtp.tom.com','smtp.sohu.com']

smtp地址數組,用於在不一樣的郵件服務器間切換。

def sendMail(sender,reciver,subject,content,passwd,smtpadd):
    username=sender
    password=passwd
    msg=MIMEMultipart('related')
    msg['Subject']=subject
    #html格式
    html=content
    htm = MIMEText(html,'html','utf-8')
    msg.attach(htm)
    #構造圖片
    fp=open(_root_dir+'Image/logo_small.png','rb')
    msgImage=MIMEImage(fp.read())
    fp.close()
    msgImage.add_header("Content-ID", "<image1>")
    msg.attach(msgImage)
    fp2=open(_root_dir+'Image/yurenjie.png','rb')
    msgImage2=MIMEImage(fp2.read())
    fp2.close()
    msgImage2.add_header('Content-Disposition', 'attachment',
                         filename="愚人節活動海報.jpg")
    msg.attach(msgImage2)
    msg['From']=sender
    msg['To']=reciver

    #發送郵件
    smtp=smtplib.SMTP()
    smtp.connect(smtpadd)
    smtp.login(username, password)
    smtp.sendmail(sender, reciver, msg.as_string())
    smtp.quit()

發郵件方法,裏面有兩個地方須要注意,一個是

msgImage.add_header("Content-ID", "<image1>")
msg.attach(msgImage)

將郵件模板中的image1的img標籤內容替換成咱們想要的圖片

第二個

    fp2=open(_root_dir+'Image/yurenjie.png','rb')
    msgImage2=MIMEImage(fp2.read())
    fp2.close()
    msgImage2.add_header('Content-Disposition', 'attachment',
                         filename="愚人節活動海報.jpg")

插入附件,圖片是一個海報,提及海報,強烈建議你們使用創客貼這個平臺,很是好用。

下面就是發送郵件啦!!!

#發送郵件
    smtp=smtplib.SMTP()
    smtp.connect(smtpadd)
    smtp.login(username, password)
    smtp.sendmail(sender, reciver, msg.as_string())
    smtp.quit()

通用方法,將文件中的以,分割的內容以數組形式返回

#讀取文件中的數據,並將使用,分割的數據變爲數組
def readFileToSplit(filepath):
    file_stream = open(filepath)
    try:
        data = file_stream.read()
    finally:
        file_stream.close()
    data_split = data.split(',')
    return data_split

主方法

一、切割帳號

二、切換郵件服務器

三、每發送一封郵件,休息25秒,切換帳號,繼續發送

四、日誌記錄

五、錯誤處理

if __name__=="__main__":
    content=_content
    # 接收人的郵箱按照天天2000封來,天天的郵箱都須要更換,文件名最後以日期爲準,郵件發送量以日誌爲準
    recivers=readFileToSplit(_root_dir+'Sendmail/mail_test.txt')
    # 把4個郵箱的帳號都獲取到,方便下面for循環中使用
    account_163=readFileToSplit(_root_dir+'Account/account163')
    account_sina=readFileToSplit(_root_dir+'Account/accountsina')
    account_tom = readFileToSplit(_root_dir+'Account/accounttom')
    account_sohu = readFileToSplit(_root_dir+'Account/accountsohu')

    # 獲取郵件發送模板
    # 注意模板之間的切換

    #log_file_stream = open(_root_dir+'log', 'w+')
    logger.info('')
    logger.info('腳本開始------------------------------------------------------------------')

    # 統計郵件發送量
    send_num = 0
    # 統計發送出錯量
    error_num = 0
    # 統計發送失敗的郵箱發送帳號
    send_success_account = []
    # 統計發送成功的郵箱發送帳號
    send_failure_account = []

    subject_num = len(_subject)

    # 最後統計沒有發出去的郵箱號,放到下日,繼續發送
    for i in range(0, len(recivers)):
        try:
            sendindex = i - error_num
            num = i % 30
            account = account_163[num].split(':')
            addindex=i%4
            subjectindex = sendindex%subject_num
            if addindex == 1:
                account=account_sina[num].split(':')
            elif addindex == 2:
                account=account_tom[num].split(':')
            elif addindex == 3:
                account=account_sohu[num].split(':')
            sender=account[0]
            passwd=account[1]
            smtpadd = _smtp_address[addindex]
            #smtpstr=str('163')
            sendMail(sender, recivers[sendindex], _subject[subjectindex], content, passwd, smtpadd)
            #print('發送帳號', sender, '正在發送')
            str_success_1 = '發送帳號【'+sender+'】正在發送'
            logger.info(str_success_1)
            #writeLog(log_file_stream,str_success_1)
            #print('接收序號', i, recivers[i],'發送成功')
            str_success_2 = '接受序號【'+str(i)+'】【'+recivers[sendindex]+'】發送成功'
            #writeLog(log_file_stream,str_success_2)
            logger.info(str_success_2)
            logger.info('')
            #print('')
            send_num+=1
            send_success_account.append(sender)
            time.sleep(25)
        except Exception as e:
            #print('中止於:', i, recivers[i],',發送失敗')
            str_failure_1 = '產生錯誤於:【'+sender+'】發送失敗'
            #writeLog(log_file_stream,str_failure_1)
            logger.error(str_failure_1)
            #print(e)
            str_failure_2 = str(e)
            #writeLog(log_file_stream,str_failure_2)
            logger.error(str_failure_2)
            logger.info('')
            error_num+=1
            send_failure_account.append(sender)
            #print('')
            #break
    #print('安全抵達底部')
    #writeLog(log_file_stream,'腳本結束')
    set(send_success_account)
    set(send_failure_account)
    logger.info('郵件總數量【'+str(len(recivers))+'')
    logger.info('總計發送郵件數量【'+str(send_num)+'')
    logger.info('總計發送錯誤數量【'+str(error_num)+'')
    logger.info('成功郵箱帳號集合:'+','.join(send_success_account))
    logger.info('失敗郵箱帳號集合:'+','.join(send_failure_account))
    logger.info('腳本結束------------------------------------------------------------------')
    logger.info('')
    #log_file_stream.close()

代碼就這麼多,至於subject郵件主題和模板怎麼搞,能夠自由發揮哈,能夠放在主執行文件中,也能夠放到配置文件中,實現能夠配置,這裏就再也不贅述啦

開工

下面就能夠開工啦,直接到項目主目錄

#python mail_html.py

看到屏幕上有輸出就OK啦,下面就是等待收穫的季節,好了,今天給你們講解了我這段時間一直在搞的兩個小玩意兒,下面開始又要回到正題了,PHP之Yii框架的詳解。但願你們都溝通交流哈~~~

相關文章
相關標籤/搜索