Compare commits

...

6 commits

Author SHA1 Message Date
Jannis Portmann d268720796 Add template message 2023-09-29 20:21:35 +02:00
Jannis Portmann 746e44942f Update readme 2023-09-29 20:21:09 +02:00
Jannis Portmann 754184628e Add requirements 2023-09-29 20:20:45 +02:00
Jannis Portmann b05a1079d6 Add venv to gitignore 2023-09-29 20:20:35 +02:00
Jannis Portmann 78e74d5ae9 Fix name 2023-04-23 13:28:58 +02:00
Jannis Portmann 4f4fc2b609 Add logging and more options 2023-04-23 13:28:51 +02:00
6 changed files with 59 additions and 16 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@ vars.py
message.html message.html
.DS_Store .DS_Store
*.pyc *.pyc
venv

View file

@ -2,16 +2,27 @@
Easily send mails via SMTP and python Easily send mails via SMTP and python
## Setup ## Installation
1. Copy `vars.py.example` to `vars.py` To install the requirements, run the following command
2. Setup `vars.py` with your credentials and config ```
3. Adapt `message.htmt` and save your contact list to `contacts.csv` python -m pip install -r requirements.txt
```
## Usage ## Usage
```python mail.py```
### Setup
1. Copy `vars.py.example` to `vars.py`
2. Setup `vars.py` with your credentials and config
3. Adapt `message.html` and save your contact list to `contacts.csv`
### Send mail
Just run
```sh
python mail.py
```
## Templating ## Templating
You can use the keys from your `csv` directly, prepending a `$` sign. For example: You can use the keys from your `csv` directly, prepending a `$` sign (case sensitive!). For example:
``` ```
Hello $name, your value is $value! Hello $name, your value is $value!
``` ```
@ -23,4 +34,14 @@ Hello h4xx0r, your value is 1337!
With a `contacts.csv` looking like: With a `contacts.csv` looking like:
| name | value | | name | value |
|--------|-------| |--------|-------|
| h4xx0r | 1337 | | h4xx0r | 1337 |
## Options
### Sending behavior
Some mail servers will block the requests, if too many are sent too fast. You can use the variables to add delays:
- `WAIT_EVERY` the amount of mails sent at once
- `DELAY_SEC` the amount of seconds to wait between sending the next batch
### Other options
- `LOGLEVEL` the logging level, set to `'DEBUG'` for most output
- `DRY_RUN` if set to `True`, the mails wont get sent, but the output is generated as if they would be sent. Good for testing and best to use with `LOGLEVEL = 'DEBUG'`

26
mail.py
View file

@ -1,10 +1,9 @@
import logging
import smtplib import smtplib
import time import time
from string import Template
from email.mime.multipart import MIMEMultipart from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText from email.mime.text import MIMEText
from string import Template
import pandas as pd import pandas as pd
@ -17,6 +16,8 @@ def get_contacts(filename):
read from a file specified by filename. read from a file specified by filename.
""" """
logging.debug(f'Loading contacts from {filename}...')
return pd.read_csv(filename) return pd.read_csv(filename)
@ -32,6 +33,10 @@ def read_template(filename):
def main(): def main():
logging.basicConfig(level=LOGLEVEL, format='%(asctime)s - %(levelname)s - %(message)s')
logging.info('Starting pymail')
contacts = get_contacts('contacts.csv') contacts = get_contacts('contacts.csv')
message_template = read_template('message.html') message_template = read_template('message.html')
@ -39,10 +44,13 @@ def main():
s = smtplib.SMTP(HOST, PORT) s = smtplib.SMTP(HOST, PORT)
s.starttls() s.starttls()
s.login(MY_ADDRESS, PASSWORD) s.login(MY_ADDRESS, PASSWORD)
logging.debug('Mail server is set up.')
logging.info(f'Starting to send mails to {len(contacts.index)} recipients, this might take a while...')
# For each contact, send the email: # For each contact, send the email:
for i in contacts.index: for i in contacts.index:
print(f"Sending email {i+1}\n") logging.info(f"Sending email {i+1} of {len(contacts.index)}\n")
msg = MIMEMultipart() # create a message msg = MIMEMultipart() # create a message
# add in the actual person name to the message template # add in the actual person name to the message template
@ -50,7 +58,7 @@ def main():
message = message_template.substitute(contact_dict) message = message_template.substitute(contact_dict)
# Prints out the message body for our sake # Prints out the message body for our sake
print(f"{message}\n") logging.debug(f"{message}\n")
# setup the parameters of the message # setup the parameters of the message
msg['From'] = MY_ADDRESS msg['From'] = MY_ADDRESS
@ -60,16 +68,20 @@ def main():
# add in the message body # add in the message body
msg.attach(MIMEText(message, 'html')) msg.attach(MIMEText(message, 'html'))
# send the message via the server set up earlier. if not DRY_RUN:
s.send_message(msg) # send the message via the server set up earlier.
s.send_message(msg)
del msg del msg
# Wait for DELAY_SEC seconds every WAIT_EVERY-th message
if (i + 1) % WAIT_EVERY == 0: if (i + 1) % WAIT_EVERY == 0:
time.sleep(DELAY_SEC) time.sleep(DELAY_SEC)
# Terminate the SMTP session and close the connection # Terminate the SMTP session and close the connection
s.quit() s.quit()
logging.info('Done!')
if __name__ == '__main__': if __name__ == '__main__':
main() main()

5
message.html Normal file
View file

@ -0,0 +1,5 @@
<html>
<body>
<p>Hello $name, your value is $value!</p>
</body>
</html>

1
requirements.txt Normal file
View file

@ -0,0 +1 @@
pandas

View file

@ -1,5 +1,5 @@
SUBJECT = '' SUBJECT = ''
EMAIL_COLUMN = '' MAIL_COLUMN = ''
MY_ADDRESS = 'example@domain.tld' MY_ADDRESS = 'example@domain.tld'
PASSWORD = 'p4ssw0rd' PASSWORD = 'p4ssw0rd'
@ -7,4 +7,7 @@ HOST = 'mail.domain.tld'
PORT = 587 PORT = 587
WAIT_EVERY = 5 WAIT_EVERY = 5
DELAY_SEC = 0 DELAY_SEC = 0
LOGLEVEL = 'INFO'
DRY_RUN = True