├── message ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ ├── countdowns.cpython-36.pyc │ ├── game_scores.cpython-36.pyc │ └── compose_message.cpython-36.pyc ├── countdowns.py ├── compose_message.py └── game_scores.py ├── LICENSE ├── email_me.py └── README.md /message/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /message/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNuge/email-report/HEAD/message/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /message/__pycache__/countdowns.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNuge/email-report/HEAD/message/__pycache__/countdowns.cpython-36.pyc -------------------------------------------------------------------------------- /message/__pycache__/game_scores.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNuge/email-report/HEAD/message/__pycache__/game_scores.cpython-36.pyc -------------------------------------------------------------------------------- /message/__pycache__/compose_message.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNuge/email-report/HEAD/message/__pycache__/compose_message.cpython-36.pyc -------------------------------------------------------------------------------- /message/countdowns.py: -------------------------------------------------------------------------------- 1 | 2 | from datetime import datetime 3 | 4 | 5 | """ these functions count out a few fun time facts for me 6 | day of my life, int(day of the year) and also time to go in my phd 7 | (aggressive timeline)""" 8 | 9 | 10 | def day_of_year(now=datetime.now()): 11 | day_of_the_year = now - datetime(now.year -1, 12, 31) 12 | date_summary = 'Today is day number %d of the year %d.\n' % (day_of_the_year.days, now.year) 13 | return date_summary 14 | 15 | def time_alive(now=datetime.now()): 16 | your_life = now - datetime(1970, 1, 1) 17 | len_existence = 'Today is day number %d of your life.\n' % (your_life.days) 18 | return len_existence 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Cam Nugent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /message/compose_message.py: -------------------------------------------------------------------------------- 1 | """ This function call all of the other functions and composes the message body. 2 | 3 | if your custom report modules are in the message folder, then the following import syntax will work: 4 | import message.YourFile as YourFile 5 | 6 | You can then call your functions inside the create_text_body() function using the syntax: 7 | YourFile.YourFunction() 8 | 9 | """ 10 | import message.countdowns as countdowns #DEMO 11 | import message.game_scores as game_scores #DEMO 12 | #from 13 | 14 | def create_text_body(): 15 | """ Call the functions that compose the email, building up the body 16 | of the message step by step and then appending these to """ 17 | body_string = '' 18 | 19 | """ this section calls the demo functions and builds up the 20 | information I want in my email report (be aware these outputs are all strings) 21 | substitute in your custom report functions here! """ 22 | day_of_the_year = countdowns.day_of_year() #DEMO 23 | day_of_my_life = countdowns.time_alive() #DEMO 24 | jays_game = game_scores.get_team_result_text('Toronto Blue Jays') #DEMO 25 | 26 | 27 | """ this section adds the strings to the message body 28 | substitute in the strings you generate here! """ 29 | body_string += 'Countdowns:\n' #DEMO 30 | body_string += day_of_the_year #DEMO 31 | body_string += day_of_my_life #DEMO 32 | body_string += '\n\n' #to add some separation #DEMO 33 | 34 | body_string += jays_game #DEMO 35 | body_string += '\n\n' #to add some separation #DEMO 36 | 37 | 38 | return body_string #return the string to email_me.py it is then written into the email 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /email_me.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import message.compose_message as compose_message 4 | 5 | import smtplib 6 | from datetime import datetime 7 | from email.mime.text import MIMEText 8 | from email.mime.multipart import MIMEMultipart 9 | 10 | """ info on where to message to and from """ 11 | fromaddr = '*****' # CHANGE TO: the email address the message will send from 12 | password = '*****' # CHANGE TO: the password for fromaddr 13 | toaddr = '*****' # CHANGE TO: the email address the message will be sent to 14 | 15 | """ set up the message""" 16 | msg = MIMEMultipart() 17 | msg['From'] = fromaddr 18 | msg['To'] = toaddr 19 | now = datetime.now() #optional, can remove if you change the subject line below 20 | msg['Subject'] = "Your report for %s" % (now.strftime('%m/%d/%Y')) #change subject line here! 21 | 22 | """ here build up the body of the text """ 23 | body = compose_message.create_text_body() #this calls compose_message to build the report 24 | msg.attach(MIMEText(body, 'plain')) #note this is plan text 25 | 26 | # advanced: you could attach images, files or other formatted data here in addition to just plain text strings! 27 | # have a look at the docs, this may take some extra work!: 28 | # https://docs.python.org/3/library/email.mime.html 29 | 30 | """ connect to the gmail server, send the email 31 | note: change the email account's settings to allow unsecure access 32 | I would recommend a new dummy email account to send the report from!""" 33 | server = smtplib.SMTP('smtp.gmail.com', 587) #this is gmail specific, for yahoo it would be: (smtp.mail.yahoo.com, 587) 34 | server.starttls() 35 | server.login(fromaddr, password) 36 | text = msg.as_string() 37 | server.sendmail(fromaddr, toaddr, text) 38 | server.quit() -------------------------------------------------------------------------------- /message/game_scores.py: -------------------------------------------------------------------------------- 1 | from urllib.request import urlopen 2 | from bs4 import BeautifulSoup 3 | 4 | """ go through the tsn website, return the game scores, and links to games involving teams 5 | that you care about. """ 6 | 7 | 8 | """ mlb """ 9 | def get_mlb_team_score(query_team): 10 | """ put in the long for name of the team of interest: 11 | i.e. 'Toronto Blue Jays', 'New York Yankees' """ 12 | baseball_reference = 'http://www.baseball-reference.com/' 13 | 14 | mlb_dat = urlopen(baseball_reference) 15 | 16 | mlb_scores= BeautifulSoup(mlb_dat, 'lxml') 17 | 18 | game_section = mlb_scores.find(id="scores") 19 | 20 | yesterday_games = game_section.findAll('',{'class','teams'}) 21 | 22 | for game in yesterday_games: 23 | winner=game.find('',{'class':'winner'}) 24 | w_team = winner.td.get_text() 25 | loser =game.find('',{'class':'loser'}) 26 | l_team = loser.td.get_text() 27 | if (w_team != query_team) and (l_team != query_team): 28 | continue 29 | else: 30 | w_score = winner.find('',{'class':'right'}).get_text() 31 | l_score = loser.find('',{'class':'right'}).get_text() 32 | 33 | return {w_team:w_score,l_team:l_score} 34 | return 'did not play yesterday' 35 | 36 | 37 | 38 | #team = 'Toronto Blue Jays' 39 | def get_team_result_text(team): 40 | yesterday_game = get_mlb_team_score(team) 41 | if yesterday_game == 'did not play yesterday': 42 | return 'The %s %s.' % (team, yesterday_game) 43 | else: 44 | other_team = [z for z in yesterday_game.keys() if z != team][0] 45 | team_score = yesterday_game[team] 46 | other_team_score = yesterday_game[other_team] 47 | if int(team_score) < int(other_team_score): 48 | result = 'Yesterday, the %s lost to the %s, %s-%s.' % (team,other_team,other_team_score,team_score) 49 | return result 50 | else: 51 | result = 'Yesterday, the %s beat the %s, %s-%s.' % (team,other_team,team_score,other_team_score) 52 | return result 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Customize a scheduled email report 2 | ### A python template to help you get a custom email report up and running. 3 | 4 | The repository is set up in a modular fashion so you can easily substitute in your own email address and report contents. I have personally found this to be a fun use for custom web scrapers that grab information off the internet and add it to an email report I have sent to myself every morning. 5 | 6 | ## What is in the repository? 7 | `email_me.py` - This is the executable file that will initiate the message composition and send the email. 8 | 9 | `message` folder: 10 | - `compose_message.py`- This file calls the message modules and composes the text of the message. 11 | - `game_scores.py` - Example module: this is a web scraper module. It acquires baseball scores from games played last night. [Look here for more info on the contents.](https://camnugent.wordpress.com/2017/08/09/139/) 12 | - `countdowns.py` - Example module: this is a series of simple countdowns. [Look here for more info on the contents.](https://camnugent.wordpress.com/2017/10/29/ttib-a-set-of-countdowns-using-python-datetime-morning-report-pt-4/) 13 | 14 | 15 | ## How do I make it work? 16 | To get the report up and running there are a few steps you need to follow: 17 | ### 1. You need an email account to send the email report from 18 | - I recommend signing up for a new gmail account for this purpose. You must allow unsecure access on the account (a no no for your main email!) 19 | - After you get a new gmail, go to the 'sign in and security' page and toggle the 'allow less secure apps' option to ON. This lets the python script send an email through the account. 20 | ### 2. Open `email_me.py` 21 | - On line 11 change the string to the email address you will be sending FROM. 22 | - On line 12 put the password for the sending email address. 23 | - On line 13 put the email address you are sending the message TO. 24 | NOTE: If you didn't use gmail, you must change the server name on line 33 to match your email host. Just google 'hostname smtp server' and you can figure this out easily. 25 | ### 3. Figure out what you want in your report! 26 | - Write some modules to scrape data from the web, provide you with links to interesting news articles, or whatever else you would like! 27 | - Write the code in functions so that they can be imported into the `compose_message.py` file and run automatically. 28 | - When you write these modules, place them in the `message` folder. 29 | - I have included two example modules for inspiration. Information on what they do can be found in posts [here](https://camnugent.wordpress.com/2017/08/09/139/) and [here](https://camnugent.wordpress.com/2017/10/29/ttib-a-set-of-countdowns-using-python-datetime-morning-report-pt-4/). 30 | ### 4. Link the report functions to the `compose_message.py` file 31 | - This file is called to build the body of the message for the email. It imports the other modules in the message folder and calls the needed functions. 32 | - There are annotations within the file to help you import and run your custom functions. 33 | ### 5. Test it out 34 | - You will likely need to tweak the message contents to get it looking how you want. 35 | - A few test calls of `email_me.py` will show you the output and help with spacing, newlines etc. 36 | - You can add new modules and import them into `compose_message.py` whenever you like, so you can easily change the report over time. 37 | - After setup, all you need to run the program is: 38 | ``` 39 | python email_me.py 40 | ``` 41 | ### 6. Run it automatically 42 | - You can set the message up to auto send. 43 | - On mac/linux the easiest way to do this is [cron](https://en.wikipedia.org/wiki/Cron) 44 | - from command line type `crontab -e` 45 | - then add a command to schedule execution. For example: to send the email report at 6am on Monday-Friday on my computer I add the command: `0 6 * * 1-5 python /Users/Cam/bin/email_me.py` 46 | - Here is the general syntax for scheduling the job so that you can get it running at the time you want: 47 | ``` 48 | * * * * * python ./email_me.py 49 | - - - - - 50 | | | | | | 51 | | | | | +----- day of week (0 - 6) (Sunday=0) 52 | | | | +------- month (1 - 12) 53 | | | +--------- day of month (1 - 31) 54 | | +----------- hour (0 - 23) 55 | +------------- min (0 - 59) 56 | ``` 57 | - If you want to get really fancy then set the program up to run in the cloud (on Amazon Web Servies, Google cloud etc.) and then you will be sent the report even if your computer is off. 58 | 59 | Thats it! A simple template for a custom email report. Feel free to take this and use it yourself! I would love to hear about any interesting scrapers or data aggregation modules that you construct and run in this template. 60 | 61 | ### Dependencies 62 | 63 | The example web scraper `game_scores.py` uses the beautiful soup package. Besides that the repository is all python3 standard library. 64 | You can download beautiful soup using: `pip install bs4` 65 | 66 | 67 | 68 | --------------------------------------------------------------------------------