Files
CyberPanel/emailMarketing/emailMarketing.py

409 lines
21 KiB
Python
Raw Normal View History

2019-12-10 23:04:24 +05:00
#!/usr/local/CyberCP/bin/python
2019-12-10 15:09:10 +05:00
2018-10-17 23:20:02 +05:00
import os
import time
import csv
import re
import plogical.CyberCPLogFileWriter as logging
2020-06-07 17:53:11 +05:00
from .models import EmailMarketing, EmailLists, EmailsInList, EmailTemplate, EmailJobs, SMTPHosts, ValidationLog
from plogical.backupSchedule import backupSchedule
2018-10-17 23:20:02 +05:00
from websiteFunctions.models import Websites
import threading as multi
import socket, smtplib
import DNS
2018-10-29 21:36:03 +05:00
from random import randint
2019-03-21 23:26:42 +05:00
from plogical.processUtilities import ProcessUtilities
2018-10-29 21:36:03 +05:00
2018-10-17 23:20:02 +05:00
class emailMarketing(multi.Thread):
def __init__(self, function, extraArgs):
multi.Thread.__init__(self)
self.function = function
self.extraArgs = extraArgs
def run(self):
try:
if self.function == 'createEmailList':
self.createEmailList()
elif self.function == 'verificationJob':
self.verificationJob()
elif self.function == 'startEmailJob':
self.startEmailJob()
2019-12-10 15:09:10 +05:00
except BaseException as msg:
2018-10-17 23:20:02 +05:00
logging.CyberCPLogFileWriter.writeToFile(str(msg) + ' [emailMarketing.run]')
def createEmailList(self):
try:
website = Websites.objects.get(domain=self.extraArgs['domain'])
try:
newList = EmailLists(owner=website, listName=self.extraArgs['listName'], dateCreated=time.strftime("%I-%M-%S-%a-%b-%Y"))
newList.save()
except:
newList = EmailLists.objects.get(listName=self.extraArgs['listName'])
counter = 0
if self.extraArgs['path'].endswith('.csv'):
with open(self.extraArgs['path'], 'r') as emailsList:
data = csv.reader(emailsList, delimiter=',')
for items in data:
2018-10-19 22:47:15 +05:00
try:
for value in items:
if re.match('^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', value) != None:
try:
getEmail = EmailsInList.objects.get(owner=newList, email=value)
except:
newEmail = EmailsInList(owner=newList, email=value,
verificationStatus='NOT CHECKED',
dateCreated=time.strftime("%I-%M-%S-%a-%b-%Y"))
newEmail.save()
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], str(counter) + ' emails read.')
counter = counter + 1
2019-12-10 15:09:10 +05:00
except BaseException as msg:
2018-10-19 22:47:15 +05:00
logging.CyberCPLogFileWriter.writeToFile(str(msg))
continue
2018-10-17 23:20:02 +05:00
elif self.extraArgs['path'].endswith('.txt'):
with open(self.extraArgs['path'], 'r') as emailsList:
emails = emailsList.readline()
while emails:
email = emails.strip('\n')
if re.match('^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', email) != None:
try:
getEmail = EmailsInList.objects.get(owner=newList, email=email)
2019-12-10 15:09:10 +05:00
except BaseException as msg:
2018-10-17 23:20:02 +05:00
newEmail = EmailsInList(owner=newList, email=email, verificationStatus='NOT CHECKED',
dateCreated=time.strftime("%I-%M-%S-%a-%b-%Y"))
newEmail.save()
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],str(counter) + ' emails read.')
counter = counter + 1
emails = emailsList.readline()
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], str(counter) + 'Successfully read all emails. [200]')
2019-12-10 15:09:10 +05:00
except BaseException as msg:
2018-10-17 23:20:02 +05:00
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], str(msg) +'. [404]')
return 0
2020-06-06 23:48:48 +05:00
def findNextIP(self):
try:
if self.delayData['rotation'] == 'Disable':
return None
elif self.delayData['rotation'] == 'IPv4':
if self.delayData['ipv4'].find(',') == -1:
return self.delayData['ipv4']
else:
ipv4s = self.delayData['ipv4'].split(',')
if self.currentIP == '':
return ipv4s[0]
else:
returnCheck = 0
for items in ipv4s:
if returnCheck == 1:
return items
if items == self.currentIP:
returnCheck = 1
return ipv4s[0]
else:
if self.delayData['ipv6'].find(',') == -1:
return self.delayData['ipv6']
else:
ipv6 = self.delayData['ipv6'].split(',')
if self.currentIP == '':
return ipv6[0]
else:
returnCheck = 0
for items in ipv6:
if returnCheck == 1:
return items
if items == self.currentIP:
returnCheck = 1
return ipv6[0]
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg))
return None
2018-10-17 23:20:02 +05:00
def verificationJob(self):
try:
verificationList = EmailLists.objects.get(listName=self.extraArgs['listName'])
domain = verificationList.owner.domain
if not os.path.exists('/home/cyberpanel/' + domain):
os.mkdir('/home/cyberpanel/' + domain)
tempStatusPath = '/home/cyberpanel/' + domain + "/" + self.extraArgs['listName']
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Starting verification job..')
counter = 1
2020-06-07 17:53:11 +05:00
counterGlobal = 0
2018-10-17 23:20:02 +05:00
allEmailsInList = verificationList.emailsinlist_set.all()
2020-06-06 23:48:48 +05:00
configureVerifyPath = '/home/cyberpanel/configureVerify'
finalPath = '%s/%s' % (configureVerifyPath, domain)
import json
if os.path.exists(finalPath):
self.delayData = json.loads(open(finalPath, 'r').read())
self.currentIP = ''
2018-10-17 23:20:02 +05:00
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.INFO, message='Starting email verification..').save()
2018-10-17 23:20:02 +05:00
for items in allEmailsInList:
if items.verificationStatus != 'Verified':
try:
email = items.email
2020-06-07 17:53:11 +05:00
self.currentEmail = email
2018-10-17 23:20:02 +05:00
domainName = email.split('@')[1]
records = DNS.dnslookup(domainName, 'MX')
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.INFO,
message='Trying to verify %s ..' % (email)).save()
2018-10-17 23:20:02 +05:00
for mxRecord in records:
# Get local server hostname
host = socket.gethostname()
2020-06-07 17:53:11 +05:00
## Only fetching smtp object
2020-06-06 23:48:48 +05:00
if os.path.exists(finalPath):
try:
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.INFO,
message='Checking if delay is enabled for verification..').save()
2020-06-06 23:48:48 +05:00
delay = self.delayData['delay']
if delay == 'Enable':
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.INFO,
message='It seems delay is enabled...').save()
2020-06-06 23:48:48 +05:00
if counterGlobal == int(self.delayData['delayAfter']):
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.INFO,
message='Sleeping for %s seconds...' % (self.delayData['delayTime'])).save()
2020-06-06 23:48:48 +05:00
time.sleep(int(self.delayData['delayTime']))
counterGlobal = 0
self.currentIP = self.findNextIP()
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.INFO,
message='IP being used for validation until next sleep: %s.' % (str(self.currentIP))).save()
2020-06-06 23:48:48 +05:00
if self.currentIP == None:
server = smtplib.SMTP()
else:
server = smtplib.SMTP(self.currentIP)
else:
if self.currentIP == '':
self.currentIP = self.findNextIP()
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.INFO,
message='IP being used for validation until next sleep: %s.' % (
str(self.currentIP))).save()
2020-06-06 23:48:48 +05:00
if self.currentIP == None:
server = smtplib.SMTP()
else:
server = smtplib.SMTP(self.currentIP)
else:
logging.CyberCPLogFileWriter.writeToFile(
'Delay not configured..')
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.INFO,
message='Delay not configured..').save()
2020-06-06 23:48:48 +05:00
server = smtplib.SMTP()
except BaseException as msg:
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.ERROR,
message='Delay not configured. Error message: %s' % (str(msg))).save()
2020-06-06 23:48:48 +05:00
server = smtplib.SMTP()
else:
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.INFO,
message='Delay not configured..').save()
2020-06-06 23:48:48 +05:00
server = smtplib.SMTP()
2020-06-07 17:53:11 +05:00
###
2020-06-06 23:48:48 +05:00
2018-10-17 23:20:02 +05:00
server.set_debuglevel(0)
# SMTP Conversation
server.connect(mxRecord[1])
server.helo(host)
server.mail('host' + "@" + host)
code, message = server.rcpt(str(email))
server.quit()
# Assume 250 as Success
if code == 250:
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.INFO,
message='Verified %s successfully.' % (email)).save()
2018-10-17 23:20:02 +05:00
items.verificationStatus = 'Verified'
items.save()
break
else:
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.ERROR,
message='Failed to verify %s. Error message %s' % (email, message.decode())).save()
2018-10-17 23:20:02 +05:00
items.verificationStatus = 'Verification Failed'
items.save()
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, str(counter) + ' emails verified so far..')
counter = counter + 1
2019-12-10 15:09:10 +05:00
except BaseException as msg:
2018-10-17 23:20:02 +05:00
items.verificationStatus = 'Verification Failed'
items.save()
counter = counter + 1
logging.CyberCPLogFileWriter.writeToFile(str(msg))
2020-06-07 17:53:11 +05:00
ValidationLog(owner=verificationList, status=backupSchedule.ERROR,
message='Failed to verify %s. Error message %s' % (
self.currentEmail , str(msg))).save()
2018-10-17 23:20:02 +05:00
2020-06-06 23:48:48 +05:00
counterGlobal = counterGlobal + 1
2020-06-07 17:53:11 +05:00
verificationList.notVerified = verificationList.emailsinlist_set.filter(verificationStatus='Verification Failed').count()
verificationList.verified = verificationList.emailsinlist_set.filter(verificationStatus='Verified').count()
verificationList.save()
2018-10-17 23:20:02 +05:00
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, str(counter) + ' emails successfully verified. [200]')
2019-12-10 15:09:10 +05:00
except BaseException as msg:
2018-10-17 23:20:02 +05:00
verificationList = EmailLists.objects.get(listName=self.extraArgs['listName'])
domain = verificationList.owner.domain
tempStatusPath = '/home/cyberpanel/' + domain + "/" + self.extraArgs['listName']
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, str(msg) +'. [404]')
2020-06-07 17:53:11 +05:00
logging.CyberCPLogFileWriter.writeToFile(str(msg))
2018-10-17 23:20:02 +05:00
return 0
def startEmailJob(self):
try:
try:
if self.extraArgs['host'] == 'localhost':
2018-10-19 22:47:15 +05:00
smtpServer = smtplib.SMTP('127.0.0.1')
2018-10-17 23:20:02 +05:00
else:
verifyHost = SMTPHosts.objects.get(host=self.extraArgs['host'])
2019-03-19 01:04:22 +05:00
smtpServer = smtplib.SMTP(str(verifyHost.host), int(verifyHost.port))
smtpServer.login(str(verifyHost.userName), str(verifyHost.password))
2018-10-17 23:20:02 +05:00
except smtplib.SMTPHeloError:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'The server didnt reply properly to the HELO greeting.')
return
except smtplib.SMTPAuthenticationError:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Username and password combination not accepted.')
return
except smtplib.SMTPException:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'No suitable authentication method was found.')
return
emailList = EmailLists.objects.get(listName=self.extraArgs['listName'])
allEmails = emailList.emailsinlist_set.all()
emailMessage = EmailTemplate.objects.get(name=self.extraArgs['selectedTemplate'])
totalEmails = allEmails.count()
sent = 0
failed = 0
2018-10-19 22:47:15 +05:00
ipFile = "/etc/cyberpanel/machineIP"
f = open(ipFile)
ipData = f.read()
ipAddress = ipData.split('\n', 1)[0]
2018-10-17 23:20:02 +05:00
## Compose Message
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import re
2018-10-29 21:36:03 +05:00
tempPath = "/home/cyberpanel/" + str(randint(1000, 9999))
2018-10-17 23:20:02 +05:00
2020-06-04 22:24:51 +05:00
emailJob = EmailJobs(owner=emailMessage, date=time.strftime("%I-%M-%S-%a-%b-%Y"),
host=self.extraArgs['host'], totalEmails=totalEmails,
sent=sent, failed=failed
)
emailJob.save()
2018-10-22 10:55:52 +05:00
2020-06-04 22:24:51 +05:00
for items in allEmails:
try:
message = MIMEMultipart('alternative')
message['Subject'] = emailMessage.subject
message['From'] = emailMessage.fromEmail
message['reply-to'] = emailMessage.replyTo
if (items.verificationStatus == 'Verified' or self.extraArgs[
'verificationCheck']) and not items.verificationStatus == 'REMOVED':
try:
2018-10-19 22:47:15 +05:00
2020-06-04 22:24:51 +05:00
removalLink = "https:\/\/" + ipAddress + ":8090\/emailMarketing\/remove\/" + self.extraArgs[
'listName'] + "\/" + items.email
messageText = emailMessage.emailMessage.encode('utf-8', 'replace')
message['To'] = items.email
2018-10-29 21:36:03 +05:00
2020-06-04 22:24:51 +05:00
if re.search(b'<html', messageText, re.IGNORECASE) and re.search(b'<body', messageText,
re.IGNORECASE):
finalMessage = messageText.decode()
2018-10-29 21:36:03 +05:00
2020-06-04 22:24:51 +05:00
self.extraArgs['unsubscribeCheck'] = 0
if self.extraArgs['unsubscribeCheck']:
messageFile = open(tempPath, 'w')
messageFile.write(finalMessage)
messageFile.close()
2018-10-22 10:55:52 +05:00
2020-06-04 22:24:51 +05:00
command = "sudo sed -i 's/{{ unsubscribeCheck }}/" + removalLink + "/g' " + tempPath
ProcessUtilities.executioner(command, 'cyberpanel')
2018-10-22 10:55:52 +05:00
2020-06-04 22:24:51 +05:00
messageFile = open(tempPath, 'r')
finalMessage = messageFile.read()
messageFile.close()
2018-10-22 10:55:52 +05:00
2020-06-04 22:24:51 +05:00
html = MIMEText(finalMessage, 'html')
message.attach(html)
2018-10-19 22:47:15 +05:00
2020-06-04 22:24:51 +05:00
else:
finalMessage = messageText
if self.extraArgs['unsubscribeCheck']:
finalMessage = finalMessage.replace('{{ unsubscribeCheck }}', removalLink)
html = MIMEText(finalMessage, 'plain')
message.attach(html)
smtpServer.sendmail(message['From'], items.email, message.as_string())
sent = sent + 1
emailJob.sent = sent
emailJob.save()
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Successfully sent: ' + str(
sent) + ' Failed: ' + str(
failed))
except BaseException as msg:
failed = failed + 1
emailJob.failed = failed
emailJob.save()
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Successfully sent: ' + str(
sent) + ', Failed: ' + str(failed))
logging.CyberCPLogFileWriter.writeToFile(str(msg))
except BaseException as msg:
failed = failed + 1
emailJob.failed = failed
emailJob.save()
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Successfully sent: ' + str(
sent) + ', Failed: ' + str(failed))
logging.CyberCPLogFileWriter.writeToFile(str(msg))
2018-10-19 22:47:15 +05:00
2018-10-17 23:20:02 +05:00
2020-06-04 22:24:51 +05:00
emailJob = EmailJobs(owner=emailMessage, date=time.strftime("%I-%M-%S-%a-%b-%Y"),
host=self.extraArgs['host'], totalEmails=totalEmails,
sent=sent, failed=failed
)
emailJob.save()
2018-10-17 23:20:02 +05:00
2020-06-04 22:24:51 +05:00
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Email job completed. [200]')
2019-12-10 15:09:10 +05:00
except BaseException as msg:
2018-10-29 21:36:03 +05:00
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], str(msg) + '. [404]')
2018-10-17 23:20:02 +05:00
return 0