import re import socket from email.header import Header from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText import sendemail_common import splunk.admin as admin import splunk.entity as en import splunk.mining.dcutils as dcu import splunk.secure_smtplib as secure_smtplib import splunk.ssl_context as ssl_context logger = dcu.getLogger() charset = "UTF-8" EMAIL_DELIM = re.compile(r'\s*[,;]\s*') def isASCII(str): for i in str: if ord(i) > 127: return False return True def toBool(strVal): if strVal == None: return False lStrVal = strVal.lower() if lStrVal == "true" or lStrVal == "t" or lStrVal == "1" or lStrVal == "yes" or lStrVal == "y" : return True return False class SendemailRestHandler(admin.MConfigHandler): def __init__(self, scriptMode, ctxInfo): admin.MConfigHandler.__init__(self, scriptMode, ctxInfo) self.shouldAutoList = False # get firs arg def gfa(self, name, defaultVal=''): if self.hasNonEmptyArg(name): val = self.callerArgs.get(name, [defaultVal])[0] if val != None: return val return defaultVal def hasNonEmptyArg(self, name): return name in self.callerArgs and self.callerArgs.get(name) != None def setup(self): if self.requestedAction == admin.ACTION_CREATE or self.requestedAction == admin.ACTION_EDIT: for arg in ['to', 'body']: self.supportedArgs.addReqArg(arg) for arg in ['cc', 'bcc', 'from', 'subject', 'format', 'username', 'password', 'server', 'use_ssl', 'use_tls']: self.supportedArgs.addOptArg(arg) userInfo = en.getEntity('/authentication/', 'current-context', sessionKey=self.getSessionKey()) if userInfo.get('username') != 'splunk-system-user': raise admin.PermissionsException("This handler can only be called by the Splunk system user.") def handleList(self, confInfo): pass def handleCreate(self, confInfo): message = MIMEMultipart() subject = self.gfa('subject') body = self.gfa('body') bodyformat = self.gfa('format', 'html') server = self.gfa('server', 'localhost') username = self.gfa('username') password = self.gfa('password') use_ssl = toBool(self.gfa('use_ssl')) use_tls = toBool(self.gfa('use_tls')) sessionKey = self.getSessionKey() sslSettings = self.getAlertActions(sessionKey) # Open debate whether we should get user and password from alert actions # username = sslSettings.get('auth_username', '') # password = sslSettings.get('clear_password', '') if isASCII(subject): message['Subject'] = subject else: message['Subject'] = Header(subject, charset) recipients = [] for t in self.callerArgs.get('to'): recipients.extend(EMAIL_DELIM.split(t)) message['To'] = ', '.join(self.callerArgs.get('to')) if self.hasNonEmptyArg('cc') : cc = [x for x in self.callerArgs.get('cc') if x != None] if len(cc) > 0: message['Cc'] = ', '.join(cc) for t in cc: recipients.extend(EMAIL_DELIM.split(t)) if self.hasNonEmptyArg('bcc'): bcc = [x for x in self.callerArgs.get('bcc') if x != None] if len(bcc) > 0: message['Bcc'] = ', '.join(bcc) for t in bcc: recipients.extend(EMAIL_DELIM.split(t)) sender = 'splunk' if self.hasNonEmptyArg('from'): sender = self.gfa('from') if sender.find("@") == -1: sender = sender + '@' + socket.gethostname() if sender.endswith("@"): sender = sender + 'localhost' message['From'] = sender message.attach(MIMEText(body, bodyformat, _charset=charset)) if use_ssl or use_tls: sslHelper = ssl_context.SSLHelper() serverConfJSON = sslHelper.getServerSettings(sessionKey) # Pass in settings from alert_actions.conf into context ctx = sslHelper.createSSLContextFromSettings( sslConfJSON=sslSettings, serverConfJSON=serverConfJSON, isClientContext=True) # send the mail if not use_ssl: smtp = secure_smtplib.SecureSMTP(host=server) else: smtp = secure_smtplib.SecureSMTP_SSL(host=server, sslContext=ctx) if use_tls: smtp.starttls(ctx) if len(username) > 0 and len(password) > 0: smtp.login(username, password) # Installed SMTP daemon may not support UTF8. # This can only be determined if SMTPNotSupportedError is raised. # Try without SMTPUTF8 option if raised. audit_msg = 'Sending email for backgrounded search job: subject="%s", sender="%s", recipients="%s", server="%s"' logger.info(audit_msg, message['Subject'], sender, str(recipients), server) # Installed SMTP daemon may not support UTF8 as well as # it may throw other exceptions also. error = sendemail_common.sendEmailWithUTF8(smtp, sender, recipients, message.as_string()) if (error is not None): logger.debug('send mail with utf8 failed. retrying without utf8 option. Error: %s', str(error)) smtp.sendmail(sender, recipients, message.as_string()) smtp.quit() def getAlertActions(self, sessionKey): settings = None try: settings = en.getEntity('/configs/conf-alert_actions', 'email', sessionKey=sessionKey) logger.debug("sendemail_handler.getAlertActions conf file settings %s" % settings) except Exception as e: logger.error("Could not access or parse email stanza of alert_actions.conf. Error=%s" % str(e)) return settings # initialize the handler admin.init(SendemailRestHandler, admin.CONTEXT_APP_AND_USER)