Six Years of Deep in the Code

six years old

In looking through my older posts, I realized that I wrote my first post, Guide for the Perplexed, six years ago yesterday.

I don’t have as much time to write as much as did during the first couple of years of this blog; I generally write two posts per month now. Even so, I hope that these posts continue to do what I originally intended when I started writing them back in 2012 – both to make available useful information that is not easily found in one place, and by combining different techniques to synthesize processes that create more value than the sums of their parts.

I have received many comments and suggestions over the years, and I have found almost all of them to be not only constructive in nature, but that they have also helped correct things about which I was mistaken and also to help provide clarity when my explanation was not as clear as it could have been. Thanks for these, and keep the comments coming – they are welcome!

The things that have changed the most are the technologies that I’ve used. When I started, I primarily wrote about ASP.NET (mostly VB.NET, with some C# .NET), and SQL Server. Though I still write about SQL Server often, I find that I tend to work with other front-end technologies more often than ASP.NET now – especially JavaScript with or without jQuery.

I am planning on getting involved with more open-source technology where possible – R seems to be a good choice. Much like Python and jQuery, I think it will be more widely used in the coming years.

Thanks for reading!

Sending an Email with Attachments using Python – Checks for Attachments Before Sending

Python logo

This is an update to a script I put together several years ago which needed some minor changes to prevent the email from being sent if there were no attachments. Also, there was a bug that would send the email whether attachments were present or not due to the presence of the archive folder in the searched folder. This code should correct that. I changed the script as little as possible, so some may criticize the duplicate if statement. If I have time, I will correct this in the near future. Even so, it should work fine as written.

# Adapted from https://gist.github.com/4009671 and other sources by David Young
# added directory searching functionality to add all files in folder
# disabled username / password logon for use in our Exchange environment

######### Setup your stuff here #######################################
servername='ServerName'
path='//' + servername + '/PathUnderServerName' # location of files
archiveFolderName = 'archive' # name of folder under path where files will be archived

host = 'smtp.example.com' # specify port, if required, using a colon and port number following the hostname

fromaddr = '[email protected]' # must be a vaild 'from' address in your environment
toaddr  = "[email protected]"
replyto = fromaddr # unless you want a different reply-to

# username = 'username' # not used in our Exchange environment
# password = 'password' # not used in our Exchange environment

msgsubject = 'Your message regarding server named ' + servername

htmlmsgtext = """<h2>Files present on server named """ + servername + """ are attached and have been archived.</h2>""" # text with appropriate HTML tags

######### In normal use nothing changes below this line ###############

import smtplib, os, sys, shutil
from datetime import date
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
from HTMLParser import HTMLParser

archivePath = os.path.join(path, archiveFolderName) # full path where files will be archived

if not os.path.exists(archivePath): # create archive folder if it doesn't exist
    os.makedirs(archivePath)
    print 'Archive folder created at ' + archivePath + '.'

# A snippet - class to strip HTML tags for the text version of the email

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.fed = []
    def handle_data(self, d):
        self.fed.append(d)
    def get_data(self):
        return ''.join(self.fed)

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

########################################################################

try:
    # Make text version from HTML - First convert tags that produce a line break to carriage returns
    msgtext = htmlmsgtext.replace('</br>',"\r").replace('<br />',"\r").replace('</p>',"\r")
    # Then strip all the other tags out
    msgtext = strip_tags(msgtext)

    # necessary mimey stuff
    msg = MIMEMultipart()
    msg.preamble = 'This is a multi-part message in MIME format.\n'
    msg.epilogue = ''

    body = MIMEMultipart('alternative')
    body.attach(MIMEText(msgtext))
    body.attach(MIMEText(htmlmsgtext, 'html'))
    msg.attach(body)
    attachments = os.listdir(path)

    if 'attachments' in globals() and len(attachments) > 1: # are there attachments?
        for filename in attachments:
            if os.path.isfile(os.path.join(path, filename)):
                f = os.path.join(path, filename)
                part = MIMEBase('application', "octet-stream")
                part.set_payload( open(f,"rb").read() )
                Encoders.encode_base64(part)
                part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
                msg.attach(part)

    msg.add_header('From', fromaddr)
    msg.add_header('To', toaddr)
    msg.add_header('Subject', msgsubject)
    msg.add_header('Reply-To', replyto)

    # The actual email sendy bits
    server = smtplib.SMTP(host)
    server.set_debuglevel(False) # set to True for verbose output

    # Comment this block and uncomment the below try/except block if TLS or user/pass is required.

    if 'attachments' in globals() and len(attachments) > 1: # are there attachments?
        server.sendmail(msg['From'], [msg['To']], msg.as_string())
        print 'Email sent.'
        #print len(attachments)-1
    else:
        print 'No attachments found.'

    server.quit() # bye bye                

    # try:
        # # If TLS is used
        # server.starttls()
        # server.login(username,password)
        # server.sendmail(msg['From'], [msg['To']], msg.as_string())
        # print 'Email sent.'
        # server.quit() # bye bye
    # except:
        # # if tls is set for non-tls servers you would have raised an exception, so....
        # server.login(username,password)
        # server.sendmail(msg['From'], [msg['To']], msg.as_string())
        # print 'Email sent.'
        # server.quit() # bye bye

except:
    print "Email NOT sent to %s successfully. ERR: %s %s %s " % (str(toaddr), str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]) )
    #just in case

try:
    if 'attachments' in globals() and len(attachments) > 1: # are there attachments?
        for filename in attachments:
            if os.path.isfile(os.path.join(path, filename)):
                f1 = os.path.join(path, filename)
                x = filename.find('.')
                filename2 = filename[:x] + '_' + str(date.today()) + filename[x:]
                f2 = os.path.join(path, filename2)
                os.rename(f1, f2)
                print "File " + filename + " renamed to " + filename2 + "."
                shutil.move(f2, archivePath)
                print "File " + filename2 + " moved to " + archivePath + "."

except:
    print "Files not successfully renamed and/or archived."

Accessing the Google Foobar Challenges on Chrome

Google Foobar challenge prompt

Last night I was Googling Python lambda functions and a strange thing happened. The Google search results window broke open near the top and a single line of white text appeared on a black background asking if I wanted to take a test, next to a link to google.com/foobar.

Google Foobar challenge prompt

After clicking on the link, I was able to login and got a shell prompt.

For some reason, some letters could be typed, but others had no effect. Initially, I was using Chrome as my browser. On Safari, I found that I could type anything there.

Ironically, Chrome’s malware defenses affect the functionality of this page. If you want to use Chrome to do the Foobar challenges, you must uncheck the “Enable phishing and malware protection” under Advanced Settings in Chrome. Some other ad blocking or malware-related extensions may also need to be turned off if this doesn’t fix the problem.