Home Depot Automated Survey Contest Entry

Published: 2021-01-31 | Tags: automation contests home depot email python imap requests

Since I have been working on remodeling our house I have been going to my local home depot like 3 times a week. Each time I get a receipt there is a code for a survey at the bottom. I've often thought that I should automate the entry of these survey's so that I could increase my chance at winning. I decided to see how hard that would be with python's requests library. Along the way I also learned how to log onto fastmail using the python imaplib and email libraries.

Odds of winning and contest rules

The official contest rules are located at the Home Depot survey site (Several screens in). Listed there are the rules, and the winners.

Odds of winning depend on number of entries

There appears to be 1 winner per quarter. So 4 winners per year in the United States. There are a bunch in Puerto Rico though, which is odd.

Contest winners

I also would like to calculate what the expected value of my time is to create something to submit the receipts. The variables necessary are:

So First calculate my chance of winning as:
120/(1,616,000,000 * x)
For x = 0.1% -> Approximate Chance of winning: 1 in 15,000

So, if 1 in 1000 receipts are submited then I have a 1 in 15k chance of winning.

Multiply times the amount of the prize ($5000) and I have an expected value of $0.37 from creating this program!. Not bad!

You can also mail in entries to the contest: Mail in contest entry rules However, based on the cost of a stamp ($0.50 or more) and the expected value per entry, I would not recommend doing this.

Step 1: Getting receipts

At first I was thinking about using requests to log into my Home Depot account and parse the receipts, however I realized that Home Depot will email your receipts to you. So I signed up for email receipts and learned how to log into my email provider (fastmail) using python's imaplib. The process should be very similiar for other email providers.

Here are the resources I used:

For fastmail: - Create an App Password - Set the App password to "IMAP"

And the fastmail settings that are needed are:

Server  imap.fastmail.com   
Port    993  
SSL/TLS Encryption  Enabled, but not STARTTLS  
Username    Your Fastmail email address, including the domain.  
Password    Your app-specific password. You cannot use your regular Fastmail password.  
Root folder/IMAP path prefix    (leave blank)  
Folder separator    / (forward slash)

For a different email provider just search for "\<email provider name> imap settings" and you should find something similiar.

Next, I created a email rule to move all receipts to the "hd" folder. That way my script could open that folder on my email, and mark receipts that it saw as read so that they would not be read multiple times.

Here is the completed script to read that email folder and print the user ID and password from the receipts.

# Will read my fastmail inbox for receipts

import imaplib
import email
from email.header import decode_header
import webbrowser
import os
import code


# account credentials
username = "<Email here>"
password = "<password here>"

# create an IMAP4 class with SSL 
imap = imaplib.IMAP4_SSL("imap.fastmail.com")

# authenticate
print("Login in....")
imap.login(username, password)

status, messages = imap.select("INBOX/hd")

number = int(messages[0])


status, response = imap.search(None, '(UNSEEN)')
number = response[0].split()
#code.interact(local=locals())

for i in number:
    # fetch the email message by ID
    num_fetch = str(i.decode('utf-8'))
    res, msg = imap.fetch(num_fetch, "(RFC822)")
    if res != "OK":
        print("Failed to get message")
    else:
        print("Got the message")
        # Mark as read
        typ, data = imap.store(num_fetch,'+FLAGS','\\SEEN')

    # Msg is a tuple with the type as the the first element
    # Get the actual message
    msg = msg[0][1]
    # Parse into email object
    msg = email.message_from_bytes(msg)
    # Get subject
    subject, encoding = decode_header(msg["Subject"])[0]
    if subject != 'Your Electronic Receipt':
        # Not a receipt email
        print("Not a receipt")
        continue 
    From, encoding = decode_header(msg.get("From"))[0]

    for part in msg.walk():
        print(part.get_content_type())
        if part.get_content_type() == "text/html":
            body = part.get_payload()
            start = body.find("User ID:")
            if start == -1:
                # Could not find user id in receipt.
                continue
            body = body[start+9:]
            uid = body[:body.find("<")]
            body = body[body.find("PASSWORD:"):]
            password = body[:body.find("<")]

            # use password and user id.
            print("Got password and id")
            print("id: "+ uid)
            print("password " +password)

# Close/logout
imap.close()
imap.logout()

Step 2: Submiting Receipts

In order to write the program to submit the receipts I used the firefox developer console to see what data was being sent in the requests the browser was making to the site:

Firefox Debug Console

Since I was doing this quickly I just copied my responses to the questions and inputs from the developer console. Some of the parameters could be move around in my script so that they are editable.

Another way my script could be expanded would be to be able to automatically fill out questions for the survey. Or be able to respond to the questions being different.

So here is the script with the parameters pulled out of the debug console and requested with python requests library

import requests
import code

# Start by creating the info to enter
zipcode = 11111

# Format so that the UID/Password have pluses
uid = "<UID>"
password = "<password>"
uid = uid.replace(" ","+")
password = password.replace(" ","+")


# Create a session to store cookies for the entire program
s = requests.Session()

# Create the URL to go to
base_url = "https://survey.medallia.com/"
start_url = base_url + "?thehomedepot"

print("[+] Getting page URL: %s" % start_url)

# This is only to get some cookies
# Otherwise we would skip to the next page
start_page = s.get(start_url)

# The button clicks with a specific url based on our cookie value
url_part = s.cookies["thehomedepot"]

# The "form" from the first page.
# This is the begin survey button
payload = "lang=en&stay_main-pager=0&currentPage=0&nodeId=survey5&ballotVer=2&hmac=&is_embedded=false&defPgrAction=next&forward_main-pager=Begin+Survey"
second_url = base_url + "?" + url_part

print("[+] Getting second url: %s" % second_url)
headers={
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Referer': 'https://survey.medallia.com/?thehomedepot'
    }


page = s.post(second_url,headers=headers,data=payload)

# The previous page asks us to enter our zip code
# Same URL as before
payload = "stay_main-pager=1&currentPage=1&nodeId=survey5&ballotVer=3&hmac=&is_embedded=false&defPgrAction=next&spl_q_thd_postalcode_entry_text=" + zipcode + "&forward_main-pager=Next" 
print("[+] Getting third page: %s" % second_url)
headers['Referer']=second_url
page = s.post(second_url,headers=headers,data=payload)


# # Click next to really start survey
payload = "stay_main-pager=2&currentPage=2&nodeId=survey5&ballotVer=4&hmac=&is_embedded=false&defPgrAction=next&forward_main-pager=Next"
print("[+] Getting 4th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)


# Enter the password and username
payload = "stay_main-pager=3&currentPage=3&nodeId=survey5&ballotVer=5&hmac=&is_embedded=false&defPgrAction=next&spl_q_thd_receiptcode_id_entry_text=" + uid + "&spl_q_thd_receiptcode_password_entry_text="+ password +"&forward_main-pager=Next"
print("[+] Getting 5th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)

# Select occupation
payload = "stay_main-pager=7&currentPage=7&nodeId=survey5&ballotVer=6&hmac=&is_embedded=false&defPgrAction=next&onf_q_thd_pro_classification_contractor_remodeling_yn=1&forward_main-pager=Next"
print("[+] Getting 6th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)

# How likely are you to shop at this HD again
payload = "stay_main-pager=9&currentPage=9&nodeId=survey5&ballotVer=7&hmac=&is_embedded=false&defPgrAction=next&onf_q_thd_shop_likely_radio=5&forward_main-pager=Next"
print("[+] Getting 7th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)

# How would you describe this particular shopping experience
payload = "stay_main-pager=12&currentPage=12&nodeId=survey5&ballotVer=8&hmac=&is_embedded=false&defPgrAction=next&onf_q_thd_shop_comparison_radio=4&forward_main-pager=Next"
print("[+] Getting 8th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)


# How satified were you with...
payload = "stay_main-pager=14&currentPage=14&nodeId=survey5&ballotVer=9&hmac=&is_embedded=false&defPgrAction=next&spl_q_thd_shop_experience_text=1.+Home+depot+app+shows+where+things+are+in+the+store.+%0D%0A2.+Home+depot+tools+are+a+little+better+%28ryobi%29%0D%0A3.+Home+depot+associates+are+generally+better%0D%0A4.+Good+selection&forward_main-pager=Next"
print("[+] Getting 9th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)


# checkout and employees
payload = "stay_main-pager=15&currentPage=15&nodeId=survey5&ballotVer=10&hmac=&is_embedded=false&defPgrAction=next&onf_q_thd_satisfied_checkout_process_radio=5&onf_q_thd_satisfied_employees_experience_radio=5&forward_main-pager=Next"
print("[+] Getting 10th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)


# Clean and in stock?
payload = "stay_main-pager=17&currentPage=17&nodeId=survey5&ballotVer=11&hmac=&is_embedded=false&defPgrAction=next&onf_q_thd_perceptions_neat_clean_radio=5&onf_q_thd_perceptions_in_stock_radio=5&onf_q_thd_perceptions_cashier_friendly_radio=5&onf_q_thd_perceptions_employee_friendly_radio=5&forward_main-pager=Next"
print("[+] Getting 11th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)

# Require / recieve assistance?
payload = "stay_main-pager=19&currentPage=19&nodeId=survey5&ballotVer=12&hmac=&is_embedded=false&defPgrAction=next&onf_q_thd_assistance_require_yn=2&onf_q_thd_assistance_receive_yn=2&forward_main-pager=Next"
print("[+] Getting 12th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)

# did an employee go above and beyond?
payload = "stay_main-pager=29&currentPage=29&nodeId=survey5&ballotVer=13&hmac=&is_embedded=false&defPgrAction=next&onf_q_thd_praise_employee_yn=2&forward_main-pager=Next"
print("[+] Getting 13th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)

# anything we could do to improve?
payload = "stay_main-pager=31&currentPage=31&nodeId=survey5&ballotVer=14&hmac=&is_embedded=false&defPgrAction=next&spl_q_thd_catchall_oe_comment=Could+start+carrying+the+concrete+countertop+mix+again.&forward_main-pager=Next"
print("[+] Getting 14th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)

# random question
payload = "stay_main-pager=38&currentPage=38&nodeId=survey5&ballotVer=15&hmac=&is_embedded=false&defPgrAction=next&onf_i_question_1=2&onf_i_question_2=1&onf_i_question_3=2&forward_main-pager=Next"
print("[+] Getting 15th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)
code.interact(local=locals())

# Finish
phone = "<phone>"
email_user = "<email username>"
email_domain = "<email domain name>"
first_name = "<First Name>"
last_name = "<Last Name>"
payload = "stay_main-pager=46&currentPage=46&nodeId=survey5&ballotVer=16&hmac=&is_embedded=false&defPgrAction=next&spl_q_thd_contact_first_name_text="+first_name+"&spl_q_thd_contact_last_name_text="+last_name+"&spl_q_thd_contact_email_sweeps_text=" + email_user + "%40"+email_domain+"&spl_q_thd_contact_phone_sweeps_text="+phone+"&forward_main-pager=Finish"
print("[+] Getting 16th page: %s" % second_url)
page = s.post(second_url,headers=headers,data=payload)

Conclusion

The only thing left to do is to write a small loop to call the submit program for each of the UID's gotten from the email.

Here is the final program: Final program

Other things you could do with this:
- Cron job to run it periodically
- Better Error checking
- Expand to Walmart's receipt contest?

Obviously, this is probably not the best use of your time if you are trying to make money. But it is a good training exercise for automating other things. Hopefully, this inspires you to find things in your life that you can automate with python/requests.