diff --git a/main.py b/main.py index 6f4f6b8..fdfb1a7 100755 --- a/main.py +++ b/main.py @@ -12,9 +12,10 @@ import pymongo # database from dotenv import load_dotenv import random, string # for tokens import html # for sanitization +import datetime # to name unsent mails -##################################################### Bottle stuff ############################################$ +##################################################### Bottle stuff ############################################ # The exception that is thrown when an argument is missing class MissingParameterException (Exception): @@ -35,7 +36,7 @@ class StripPathMiddleware(object): app = application = bottle.Bottle(catchall=False) -##################################################### Configuration ############################################$ +##################################################### Configuration ############################################ def get_env(var, default=None): """var is an env var name, default is the value to return if var does not exist. If no default and no value, an exception is raised.""" if var in os.environ: @@ -51,7 +52,7 @@ token_chars = string.ascii_lowercase+string.ascii_uppercase+string.digits token_len = 50 # form template regex -form_regex = '\{\{(\w+)(\|\w+)?\}\}' +form_regex = '\{\{(\w+)(\|[\w\s,\.\?\'\"\!\[\]]+)?\}\}' # Load file from .env file. load_dotenv(os.path.dirname(__file__) + '.env') @@ -87,7 +88,7 @@ mongodb_client = pymongo.MongoClient("mongodb://{}:{}/".format(mongodb_host, mon mongodb_database = mongodb_client[mongodb_dbname] -##################################################### main route: mail submission ############################################$ +##################################################### main route: mail submission ############################################ @app.post('/submit') def submission (): @@ -123,23 +124,35 @@ def submission (): subject = re.sub(form_regex, r'{\1}', form['subject']).format(**subject_fields) content = re.sub(form_regex, r'{\1}', form['content']).format(**content_fields) - print(subject) - print(content) try: if not send_mail(from_address, form['mail'], subject, content): response.status = 500 return 'Le mail n’a pas pu être envoyé.' - except SMTPDataError as e: + except smtplib.SMTPDataError as e: + save_mail (token, form['mail'], from_address, subject, content) response.status = 500 - return 'Le mail a été refusé.' + error = 'Le mail a été refusé. Votre message a été enregistré, il sera remis manuellement à son destinataire.' + except smtplib.SMTPRecipientsRefused as e: + save_mail (token, form['mail'], from_address, subject, content) + response.status = 500 + error = 'Impossible de trouver le destinataire du mail. Votre message a été enregistré, il sera remis manuellement à son destinataire.' + # Redirection #redirect(success_redirect_default) origin = request.headers.get('origin') return '

Mail envoyé !

' + ('

Retour au formulaire de contact

'.format(origin) if origin else '') -##################################################### Helpers ############################################$ +##################################################### Helpers ############################################ +def save_mail (token, to, from_address, subject, content): + with open('unsent/unsent_{}_{}_{}.txt'.format(str(datetime.datetime.now()), token, to), 'w') as f: + f.write("Unsent mail\nSubject: {}\nFrom: {}Content:\n{}".format( + subject, + from_address, + content + )) + def get_fields (string): """ Parse the string looking for template elements and create an array with template to fill and their default values. None if mandatory. """ result = {} @@ -206,7 +219,7 @@ def login(request): return {'_privilege': 1000} # anonymous -##################################################### Forms ############################################$ +##################################################### Forms ############################################ @app.post('/form') def create_form (): @@ -304,7 +317,7 @@ def delete_form(token): return 'Privilèges insufisants' -##################################################### Users ############################################$ +##################################################### Users ############################################ @app.post('/user/list') def list_users (): @@ -365,7 +378,7 @@ def delete_user (username): -##################################################### app startup ############################################$ +##################################################### app startup ############################################ if __name__ == '__main__': bottle.run(app=StripPathMiddleware(app), host=listen_address, port=listen_port, debug=True) else: diff --git a/readme.md b/readme.md index 0a1951f..d12298e 100644 --- a/readme.md +++ b/readme.md @@ -12,6 +12,7 @@ But the first limitation is… No interractions… So no contact form… That wo - Create or reuse an existing contact form - Add the `action` parameter to the mailer address + `/submit` - Get a token from this mailer app and place it in your form like : + ```
@@ -67,6 +68,13 @@ UID=1000 ``` You can store them in a `.env` file. The python app will read it or you can pass it to the docker container with `run` option `--env-file`. +- `SMTP_*` are used to connect to the smtp server that will send the mail. +- `SMTP_SSL` is used to enable SSL +- `SMTP_STARTTLS` is used to enable STARTTLS if `SMTP_SSL` is not defined. In no ssl and starttls are defined the app wont connect. +- `MONGODB_HOST` the host to connect to mongodb +- `ADMIN_PASSWORD` password used to manage users +- `UID` used to set the uwsg socket ownership in production + ## Roadmap ### Near future - go on docker hub @@ -78,4 +86,4 @@ You can store them in a `.env` file. The python app will read it or you can pass ### Ameliorations - Use real user/passwords accounts - +- Créate a gui client