I have a text based program which uses menus and sub-menus in a 'while True:' style loop. You get to the sub menu via the top menu - EDITED to include the code.

When I make a menu selection

```
def main():   
    import win32com.client, os, datetime, time, sys

    outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")

    try: #THIS IS NOT THE TRY/EXCEPT BLOCK CAUSING ISSUES
        itinbox = outlook.Folders("IT Department").Folders('Inbox')#Look at inbox of IT Dept inbox
        itcontents = itinbox.Items #messages in the inbox        
        newMail = itcontents.GetLast() #GetLast is the most RECENT email.
        nextMail = itcontents.GetPrevious() #The next most recent email after .GetLast()
        mailSubj = newMail.Subject #The subject header
        #total number of emails in the inbox
        totalEmails = itcontents.Count
        #print("Most recent mail:", newMail) #subject header of most recent email
        #print("sent from:", newMail.Sender)

    except UnicodeEncodeError: #unsupported characters
        print("Most recent message had unsupported characters.")

    emailUser = os.getlogin()
    print("Current user is", emailUser)

    #Get todays date based on system clock
    todayDate = datetime.date.today()

    senderDict = {email address : name} #redacted

    listSender = list(senderDict.values())
    listSender.insert(0, "Search Any")

    def topMenu():
        topMenuItems = ['Collect Attachments', 'View Senders', 'Edit Senders', 'Quit']

        while True:
            try:
                for count, item in enumerate(topMenuItems,1):
                    print(count, item)
                mainChoice = int(input('\nChoose an option: ')) #subtract one to match enumerate to INDEX
                mainChoice -= 1
                print("Chose", topMenuItems[mainChoice], "\n")

                ###Collect Attachments
                if mainChoice == 0:
                    mainChoice0()
                    #break

                elif mainChoice == 1:
                    print(senderDict, "\n")
                    input("Press any key")
                    continue

                elif mainChoice == 2:
                    print("coming soon\n")
                    continue

                elif mainChoice == 3:
                    input("Press any key to exit.")
                    sys.exit("Goodbye")

            except ValueError: #Not int
                print("You did not enter a valid number (ValueError)")
                continue

            except AttributeError:
                print("You did not enter a valid number (AttributeError)")
                continue

            except IndexError: #outside range
                print("Selection was not in the list (IndexError)")
                continue

    def mainChoice0(): #Collect Attachments
        check = 0 #Keep count of checked messages
        while True:
            try:
                ####Determine search range by date
                startDate = input("Enter a date dd-mm-yyyy: ")
                while startDate == "":
                    startDate = input("Enter a date dd-mm-yyyy: ")

                #strptime will convert startDate from a string to a usable date
                startDate = datetime.datetime.strptime(startDate, "%d-%m-%Y") #class and module are called datetime hence datetime.datetime.strptime
                searchRange = int(input("Enter how many days previous to search through: "))
                searchDate = startDate.date() - datetime.timedelta(days = searchRange)
                print("Your search starts from", startDate, "and ends on", searchDate, "\n")

                #display list of senders for mainChoice == 0
                for count, item in enumerate(listSender,0): 
                    print(count, item)
                print("There are", len(listSender), "options.\n")

                ########### Choose option from listSender
                for msg in reversed(itcontents): #reversed() will go from most recent to oldest email based on date
                    if msg.Class == 43: #only search mail items (class 43)
                        #Make a folder on user desktop if it doesn't exist
                        if not os.path.exists("C:\\Users\\"+emailUser+"\\Desktop\\Invoices from Outlook\\"):
                            os.makedirs("C:\\Users\\"+emailUser+"\\Desktop\\Invoices from Outlook\\")
                            print("Created folder 'Invoices from Outlook' on user desktop.")

                        #Choose sender, reference index to name.
                        senderNum = int(input("Choose a sender (blank to exit): "))
                        senderChoice = listSender[senderNum]

                        #Search all
                        if senderNum == 0:
                            print("Searching for any sender")
                            #####Code to check emails runs after choosing a sender
                            #msg refers to a mail item object

                            if ( (str(msg.SenderEmailAddress) or str(msg.Subject) or str(msg.Sender) or str(msg.SentOnBehalfOfName)) in senderDict and (msg.SentOn.date() >= searchDate and msg.SentOn.date() <= startDate.date())):
                                check += 1
                                print(check, "messages from", msg.SenderEmailAddress, "on", msg.SentOn.date())

                                #Check attachment file format string, invoices are usually PDFs.
                                #x refers to the attachment. Not every message from a listed sender has an attachment, those messages still add to count check.
                                for x in msg.Attachments:
                                    if str(".pdf").casefold() in str(x): #casfold() checks possible upper or lower case combinations e.g PdF or pDf
                                        x.SaveAsFile("C:\\Users\\"+emailUser+"\\Desktop\\Invoices from Outlook\\" + str(msg.SentOn.date()) + str(msg.SenderEmailAddress) + x.FileName)
                                        print("Saved attachment", x, "from", str(msg.Sender()), "on", str(msg.SentOn.date()))
                                        #break
                                        #Stop searching inbox earlier than searchDate
                                        if msg.SentOn.date() < searchDate: 
                                            break
                            else: print("There were", check, "messages.")
                                #break

                        elif senderNum <= len(listSender) and senderNum > 0:
                            print("you chose", senderChoice)
                            ##################### Search for a specific sender
                            ##################### Need to match chosen sender to dictionary so as to only save pdfs from that sender
                            #senderNum != 0 for all other valid options.
                            #https://www.programiz.com/python-programming/methods/built-in/any
                            #list comprehension [x for x in [items] if y in x] https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Comprehensions.html
                            if ( (str(msg.SenderEmailAddress) or str(msg.Subject) or str(msg.Sender) or str(msg.SentOnBehalfOfName)) in senderDict
                            and
                            (msg.SentOn.date() >= searchDate and msg.SentOn.date() <= startDate.date())
                            and
                            any([field for field in [str(msg.SenderEmailAddress), str(msg.Subject), str(msg.Sender), str(msg.SentOnBehalfOfName)] if str(senderChoice) in field])
                            ):
                                check += 1
                                print(check, "messages from", msg.SenderEmailAddress, "on", msg.SentOn.date()) #keep count of checked messages

                                #Check attachment file format, invoices are usually PDFs
                                #x refers to the attachment. Not every message from a listed sender has an attachment, those messages still add to count check.
                                for x in msg.Attachments:
                                    if str(".pdf").casefold() in str(x): #casfold() cheks upper or lower case format
                                            x.SaveAsFile("C:\\Users\\"+emailUser+"\\Desktop\\Invoices from Outlook\\" + str(msg.SentOn.date()) + str(msg.SenderEmailAddress) + x.FileName)
                                            print("Saved attachment", x, "from", str(msg.Sender()), "on", str(msg.SentOn.date()))

                                #Stop searching inbox earlier than searchDate
                                if msg.SentOn.date() < searchDate: 
                                    break
                            else: print("There were", check, "messages from", senderChoice)

                        elif ( senderNum != 0 
                        and 
                        ( str(msg.SenderEmailAddress) or str(msg.Subject) or str(msg.Sender) or str(msg.SentOnBehalfOfName)) in senderDict
                        and
                        (msg.SentOn.date() >= searchDate and msg.SentOn.date() <= startDate.date())
                        and
                        any([field for field in [str(msg.SenderEmailAddress), str(msg.Subject), str(msg.Sender), str(msg.SentOnBehalfOfName)] if str(senderChoice) in field])
                        ):
                            check += 1
                            print(check, "messages from", msg.SenderEmailAddress, "on", msg.SentOn.date()) #keep count of checked messages

                            #Check attachment file format, invoices are usually PDFs
                            #x refers to the attachment. Not every message from a listed sender has an attachment, those messages still add to count check.
                            for x in msg.Attachments:
                                if str(".pdf").casefold() in str(x): #casfold() cheks upper or lower case format
                                        x.SaveAsFile("C:\\Users\\"+emailUser+"\\Desktop\\Invoices from Outlook\\" + str(msg.SentOn.date()) + str(msg.SenderEmailAddress) + x.FileName)
                                        print("Saved attachment", x, "from", str(msg.Sender()), "on", str(msg.SentOn.date()))
                                #break
                                #Stop searching inbox earlier than searchDate
                                if msg.SentOn.date() < searchDate: 
                                    break

            except UnicodeEncodeError: #unsupported characters
                print("Subject line could not be parsed.")

            except AttributeError: #The email was the wrong class for the attribute msg.Sender or you tried to use an attribute that doesn't work for that method
                print("Attribute error (not class 43 mail) for item from", msg.SentOn.date())
                continue

    topMenu()
main()

```

Output looks like:

```
1 Collect Attachments
2 View Senders
3 Edit Senders
4 Quit

Choose an option: 1
Chose Collect Attachments

Enter a date dd-mm-yyyy: 21-01-2020
Enter how many days previous to search through: 7
Your search starts from 2020-01-21 00:00:00 and ends on 2020-01-14

0 Search Any
1 Hazel Blue
2 Duo Security
3 Esker Australia Pty Ltd
4 iiNet Billing Team
5 TeamViewer Sales
6 ple.com.au Gnangara Warehouse Team
7 info@thereceptionist.com.au
8 Amazon Web Services
There are 9 options.

Choose a sender (blank to exit):
You did not enter a valid number (ValueError)

```

The issue is that the ValueError is not meant to be occurring in the sub menu. This is all self taught so I figure I don't understand something about how exception handling is done.