Generate a text file representing an email for a job application followup 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.
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? :)