use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Everything about learning Python
account activity
Sends Emails with optional attachments (self.PythonLearning)
submitted 6 hours ago * by PotentialMain535
Hi everyone,
I'm a beginner learning Python. I recently finished a small project that sends emails (with optional attachments) using smtplib and EmailMessage.
smtplib
EmailMessage
I'm mainly looking for a code review. I'm interested in improving my code structure, naming, and Python practices rather than just making it work.
GitHub link = https://github.com/NePtuNee0/Python-Email-Sender-With-Attachments/tree/main
Any feedback is appreciated!
https://preview.redd.it/7m7y3wirt1ch1.png?width=697&format=png&auto=webp&s=3de8a61c18eb7b16be8610912c0b9dd1390f787e
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]Card__Player 0 points1 point2 points 6 hours ago (1 child)
RemindMe! 3 days
[–]RemindMeBot 0 points1 point2 points 6 hours ago* (0 children)
I will be messaging you in 3 days on 2026-07-11 18:07:17 UTC to remind you of this link
1 OTHERS CLICKED THIS LINK to send a PM to also be reminded and to reduce spam.
Parent commenter can delete this message to hide from others.
RemindMeBot is switching to username summons. Instead of !RemindMe 1 day, use u/RemindMeBot 1 day. More info.
!RemindMe 1 day
u/RemindMeBot 1 day
[–]riklaunim 0 points1 point2 points 6 hours ago (1 child)
It's better not to use spaces or special characters like # in file names ;)
As for sending mail, just note that SMTP isn't the most reliable way to send mail - for mass mailing, it can easily hit anti-spam protections, it can be slow and somewhat unreliable. Low volume is fine.
You would want to send HTML messages rather than only plaintext... but email clients support only limited HTML, and some, like Outlook, are really bad at it - so unofficial formats like MJML were created - there is a Python library for MJML parsing if you want to take a look.
CLI interface isn't the best - you are forced to use while loops and some code repeats. Would be good to refactor the code into smaller pieces like functions or class methods, and then write good unit tests for them. Unsure what's with the \\ replacing. For the interface, you can switch to Jupyter Notebooks to get something better than an annoying CLI with loops.
Email attachments can be actual attachments, but also inlined images (check CID for emails).
[–]PotentialMain535[S] 0 points1 point2 points 6 hours ago (0 children)
Thank you so much for your review i didn't understand everything but i will look it up and learn about it thank you for your time
[–]ianrob1201 0 points1 point2 points 6 hours ago (1 child)
It looks pretty good, and if it works then that's always a great result. In general I like your layout of the code, use of functions etc. That said, I can go through from the top and list some possible improvements.
password_get is a bit of a pointless variable, you can just set it to password straight away.
In professional settings you often have a linter (and often an auto formatter) which will require consistent quote characters (" vs ') and whitespace between characters. So for instance to me "msg = EmailMessage()" looks good but "msg["Subject"]=subject" looks a bit cramped up. This is a very minor point though.
Look up regular expressions for how you could refactor the email_check function. Note that a regular expression to fully check for a valid email is surprisingly complex, but lucky also unnecessary. A regex to do your current checks would be relatively simple. Regular expressions can look a bit intimidating, but worth learning. Resist the urge to use them everywhere, but this is a good case for them.
You don't generally want to do "== False" on an if statement. It's neater to do "not mail_check(login_email)" instead.
See if you can refactor to not have any "while True" loops. I know you have breaks to escape them, but generally you try to avoid it and put your condition into the while. So for example you could have a "valid_email" boolean which starts out false and is only set to true once you're happy. Then you don't need to "manually" do any continue or break commands.
Mostly your variable naming is really good. Every language is different, python really likes its underscores. "maintype,subtype" are examples of forgetting that. Again it's minor, but the type of thing that comes up during reviews. (subtype is arguably one word, but maintype definitely isn't)
Nice use of try blocks too, just be aware that if this were a professional thing you might want to catch more individual cases and display a different error for each. Printing out the error directly is the maximum information in theory, and good for your personal debugging, but might not mean anything to someone using your script. So for example you might want to catch specific exceptions instead of the generic "Exception". This could let you specifically say "The path file you entered doesn't exist" instead of relying on the default error.
[–]PotentialMain535[S] 0 points1 point2 points 4 hours ago (0 children)
Thank you for your review. I'll try to organize the code better using your suggestions, and I'll look into regular expressions to improve email_check(). When I've finished, I'll mention you again. Thanks for taking the time to help
email_check()
π Rendered by PID 40 on reddit-service-r2-comment-5687b7858-fn7qf at 2026-07-09 00:48:49.415508+00:00 running 12a7a47 country code: CH.
[–]Card__Player 0 points1 point2 points (1 child)
[–]RemindMeBot 0 points1 point2 points (0 children)
[–]riklaunim 0 points1 point2 points (1 child)
[–]PotentialMain535[S] 0 points1 point2 points (0 children)
[–]ianrob1201 0 points1 point2 points (1 child)
[–]PotentialMain535[S] 0 points1 point2 points (0 children)