0
\$\begingroup\$

Purpose: After you've submitted a resume and cover letter for a job position, you haven't heard anything back, so you decided to send a follow up email. The script generates the follow up e-mail based on this template.

"""
    followupemail.py

    A script to generate a follow up e-mail after a job application submission.

    Based on this example: https://www.themuse.com/advice/how-to-follow-up-on-a-job-application-an-email-template

"""


def determine_if_string_is_blank(stringtovalidate, parameterType):

    """
        Determine if the stringtovalidate parameter is empty, and if so,
        raise an exception.

        Args:
            stringtovalidate: The string to validate.
            parameterType: What the stringtovalidate parameter represents in your program.

        Returns:
            None. Raises an exception.
    """

    if not stringtovalidate:
        raise ValueError ("{0} is empty", parameterType)


def prompt_user_with_question(question, parameterType):

    """
        Prompt user with a question and call determine_if_string_is_blank to deteremine
        if an answer is empty.

        Args:
            question: the question we're going to ask
            parameterType: What the stringtovalidate parameter represents in your program.

        Returns:
            answer: the string that contains our user answer.

    """

    answer = input(question)
    determine_if_string_is_blank(answer, parameterType)
    return answer


def write_string_to_file(pathtofile,email):

    """
        Writes the email to a .txt file

        Args:
            pathtofile: The path where the e-mail will be stored
            email: The message we're going to write.

        Returns:
            None
    """

    with open(pathtofile, 'w') as f:
        f.write(email)


def main():

    position_title = None
    hiring_manager = None
    company_name = None
    your_name = None

    pathtofile = "email.txt"

    company_name = prompt_user_with_question("Company Name: ", "Company Name").strip()
    position_title = prompt_user_with_question("Position: ", "Position").strip()
    hiring_manager = prompt_user_with_question("Hiring Manager: ", "Hiring Manager")
    your_name = prompt_user_with_question("Your Name: ", "Your Name")

    email = f"Hi {hiring_manager},\n\nI hope all is well. I know how busy you probably are, but I recently applied to the \n" \
         f"{position_title} position, and wanted to check in on your decision timeline.\n\n" \
         f"I am excited about the opportunity to join {company_name} (insert additional details here).\n\n" \
         f"Please let me know if it would be helpful for me to provide " \
         f"any additional information as you move on to the next stage in the hiring process.\n\nI look forward to hearing from you,\n\n{your_name}"

    write_string_to_file(pathtofile,email)


if __name__ == "__main__":
    main()

Explanation: The script prompts the user for company name, position, hiring manager, and the name. It inserts those values into the email string and generates a text file.

\$\endgroup\$
1
\$\begingroup\$

You wrote a lot of boilerplate code to do a simple task. Before reading the rest of this review, scroll back up and imagine that you were given the assignment, "Make your code as simple and readable as possible." What would you change about it?

Here's what I'd do.


def determine_if_string_is_blank(stringtovalidate, parameterType):

Inconsistent style. Pick one of snake_case, amoebacase, or camelCase, and stick to it!

This function triggers my "boolean functions should be named with is_ detector. Surely, I think, this function should be named is_blank_string! But in fact your name is (currently) more appropriate, because this function does not return a boolean — it returns None or throws an exception! This is not great design, but, okay, the name isn't the worst. However, I would write this entire function as

def assert_string_isnt_blank(s)
    assert s

(notice that the name of the function now unambiguously tells what it does) and then I would eliminate it.

def prompt_user_with_question(question, parameterType):
    answer = input(question)
    assert answer, f"{parameterType} is empty"
    return answer

By the way, what did you expect this line to do?

raise ValueError ("{0} is empty", parameterType)

Did you perhaps expect it to do the same thing as

raise ValueError ("{0} is empty".format(parameterType))

? It doesn't!

(This suggests that you never tested your code, or at least you never tested its non-success paths. Make sure to test your code before running it in production — or posting it to StackExchange!)


def write_string_to_file(pathtofile,email):

The usual complaint about needing to pick a style (underscores? no underscores?) and sticking to it. But also there's a missing space here. It would be good to get in the habit of running your code through a linter like flake8 before posting it, as well.

$ flake8 --ignore=E501 x.py
x.py:26:25: E211 whitespace before '('
x.py:49:36: E231 missing whitespace after ','
x.py:81:10: E127 continuation line over-indented for visual indent
x.py:86:36: E231 missing whitespace after ','

Nothing major here... but sometimes there is something major, and then you're glad you took the time to look for warnings!


Your docstrings make it look like you're intending this as a 100% complete Python program. If so, then you should start the file with a hashbang:

#!/usr/bin/env python

For the email body itself, consider using """multi-line strings""" instead of backslash-continuations. Multi-line strings can be combined with the f prefix.


position_title = None
hiring_manager = None
company_name = None
your_name = None

You create all these variables and then you never use them again! Or, another way to put it is, you assign None to all these variables and then immediately overwrite it with some other value! Eliminate the dead writes.


In conclusion:

#!/usr/bin/env python

def prompt(question):
    answer = input(question + ": ")
    assert answer, f"{question} is empty"
    return answer

if __name__ == "__main__":
    company_name = prompt("Company Name").strip()
    position_title = prompt("Position").strip()
    hiring_manager = prompt("Hiring Manager")
    your_name = prompt("Your Name")

    with open("email.txt", "w") as f:
        f.write(f"""
Hi {hiring_manager},

I hope all is well. I know how busy you probably are, but I recently applied to the
{position_title} position, and wanted to check in on your decision timeline.

I am excited about the opportunity to join {company_name} (insert additional details here).

Please let me know if it would be helpful for me to provide
any additional information as you move on to the next stage in the hiring process.

I look forward to hearing from you,
{your_name}
        """.strip() + '\n')

Notice that I'm using a function only when it makes sense — that is, only when it eliminates repetition in the code.

Also notice that by using a multi-line string, even though it screws up my indentation, it helps to highlight an otherwise-easily-missed bug in the program!

I am excited about the opportunity to join {company_name} (insert additional details here).

Did you notice the (insert additional details here) stuffed in the middle of a string literal full of backslashes? You wouldn't want to send the email out like that, would you? :)

\$\endgroup\$
  • \$\begingroup\$ This is not great design - could you elaborate? Do you mean raising the exception? You wouldn't want to send the email out like that, would you? This is why I generate a text file rather than send an email in the script. The user may want to add more details, sometimes it's good to proof read and let something you write sit a while, because you may think of a better way to say it later on. \$\endgroup\$ – user191400 Jan 30 at 17:52
  • \$\begingroup\$ Another thing I missed too, I never enclosed my code with try/catch even though I raised an exception! I'm using Python on Windows, do still need the #!/usr/bin/env python line? \$\endgroup\$ – user191400 Jan 30 at 17:56
  • \$\begingroup\$ Re Windows: The hashbang can't hurt, and would help if you use Cygwin or git-bash or any other Unix-alike shell. I don't know if PowerShell cares; I imagine CMD doesn't. Re great design: google the phrase "exceptions for control flow." \$\endgroup\$ – Quuxplusone Jan 30 at 18:16
  • \$\begingroup\$ Given that I don't want the program to continue if a value is blank, wouldn't an exception be appropriate? Suppose if I had a Message class, obviously in the constructor I would validate that the values are not null and throw an exception if they are. \$\endgroup\$ – user191400 Jan 30 at 18:24
  • 1
    \$\begingroup\$ Assertions should be used to declare facts that the programmer knows must be true, due to the logic. They should never be used to specify conditions that the programmer hopes to be true, such as input validation. The assertions will be omitted when Python code is optimized with the -O flag, and then the program will break! \$\endgroup\$ – 200_success Jan 30 at 20:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy