├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── app.py ├── form_contact.py └── templates ├── application.html └── views ├── contacts └── contact.html ├── home └── index.html └── partials └── _header_top.html /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/python 3 | # Edit at https://www.gitignore.io/?templates=python 4 | 5 | ### Python ### 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | share/python-wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | MANIFEST 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .nox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *.cover 54 | .hypothesis/ 55 | .pytest_cache/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | db.sqlite3 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | .python-version 88 | 89 | # celery beat schedule file 90 | celerybeat-schedule 91 | 92 | # SageMath parsed files 93 | *.sage.py 94 | 95 | # Environments 96 | .env 97 | .venv 98 | env/ 99 | venv/ 100 | ENV/ 101 | env.bak/ 102 | venv.bak/ 103 | 104 | # Spyder project settings 105 | .spyderproject 106 | .spyproject 107 | 108 | # Rope project settings 109 | .ropeproject 110 | 111 | # mkdocs documentation 112 | /site 113 | 114 | # mypy 115 | .mypy_cache/ 116 | .dmypy.json 117 | dmypy.json 118 | 119 | # Pyre type checker 120 | .pyre/ 121 | 122 | ### Python Patch ### 123 | .venv/ 124 | 125 | # End of https://www.gitignore.io/api/python 126 | 127 | # Editor directories and files 128 | .idea 129 | .vscode 130 | *.suo 131 | *.ntvs* 132 | *.njsproj 133 | *.sln 134 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 GilcierWeb 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # contact-form-python-flask 2 | Contact form and send mail with Python and Flask 3 | 4 | ### Skills 5 | 6 | * Python 7 | * Flask 8 | * HTML 9 | * CSS 10 | * Bootstrap 11 | 12 | 13 | ```shell 14 | pip3 install Flask 15 | pip3 install Flask-WTF 16 | pip3 install Flask-Mail 17 | 18 | cd /contact-form-python-flask 19 | 20 | python3 app.py flask run 21 | 22 | #run localhost:5000 23 | 24 | ``` 25 | 26 | http://gilcierweb.com.br 27 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilcierweb/contact-form-python-flask/f7ad84e4ad7b2751f967b1066286ab746823cf21/__init__.py -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | from flask import Flask, render_template, request, redirect 4 | from flask_mail import Mail, Message 5 | 6 | from form_contact import ContactForm, csrf 7 | 8 | mail = Mail() 9 | 10 | app = Flask(__name__) 11 | 12 | SECRET_KEY = os.urandom(32) 13 | app.config['SECRET_KEY'] = SECRET_KEY 14 | csrf.init_app(app) 15 | 16 | app.config['MAIL_SERVER']='smtp.gmail.com' 17 | app.config['MAIL_PORT'] = 465 18 | app.config['MAIL_USERNAME'] = 'yourId@gmail.com' 19 | app.config['MAIL_PASSWORD'] = '*****' 20 | app.config['MAIL_USE_TLS'] = False 21 | app.config['MAIL_USE_SSL'] = True 22 | 23 | mail.init_app(app) 24 | 25 | @app.route('/') 26 | def index(): 27 | return render_template('views/home/index.html') 28 | 29 | @app.route('/contact', methods=['POST', 'GET']) 30 | def contact(): 31 | form = ContactForm() 32 | if form.validate_on_submit(): 33 | print('-------------------------') 34 | print(request.form['name']) 35 | print(request.form['email']) 36 | print(request.form['subject']) 37 | print(request.form['message']) 38 | print('-------------------------') 39 | send_message(request.form) 40 | return redirect('/success') 41 | 42 | return render_template('views/contacts/contact.html', form=form) 43 | 44 | @app.route('/success') 45 | def success(): 46 | return render_template('views/home/index.html') 47 | 48 | def send_message(message): 49 | print(message.get('name')) 50 | 51 | msg = Message(message.get('subject'), sender = message.get('email'), 52 | recipients = ['id1@gmail.com'], 53 | body= message.get('message') 54 | ) 55 | mail.send(msg) 56 | 57 | if __name__ == "__main__": 58 | app.run(debug = True) -------------------------------------------------------------------------------- /form_contact.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm, CSRFProtect 2 | from wtforms import StringField, TextAreaField, SubmitField 3 | from wtforms.validators import DataRequired, Email 4 | 5 | csrf = CSRFProtect() 6 | 7 | class ContactForm(FlaskForm): 8 | name = StringField('Nome', validators=[DataRequired('Nome não pode ficar vazio')]) 9 | email = StringField('E-mail', validators=[DataRequired('E-mail não pode ficar vazio'),Email('Informe um email válido')]) 10 | subject = StringField('Assunto', validators=[DataRequired('Assunto não pode ficar vazio')]) 11 | message = TextAreaField('Mensagem', validators=[DataRequired('Mensagem não pode ficar vazio')]) 12 | submit = SubmitField("Enviar") -------------------------------------------------------------------------------- /templates/application.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |Something short and leading about the collection below—its contents, the creator, etc. 8 | Make it short and sweet, but not too short so folks don’t simply skip over it entirely.
9 |10 | Main call to action 11 | Secondary action 12 |
13 |This is a wider card with supporting text below as a natural lead-in to additional 29 | content. This content is a little bit longer.
30 |This is a wider card with supporting text below as a natural lead-in to additional 49 | content. This content is a little bit longer.
50 |This is a wider card with supporting text below as a natural lead-in to additional 69 | content. This content is a little bit longer.
70 |This is a wider card with supporting text below as a natural lead-in to additional 90 | content. This content is a little bit longer.
91 |This is a wider card with supporting text below as a natural lead-in to additional 110 | content. This content is a little bit longer.
111 |This is a wider card with supporting text below as a natural lead-in to additional 130 | content. This content is a little bit longer.
131 |This is a wider card with supporting text below as a natural lead-in to additional 151 | content. This content is a little bit longer.
152 |This is a wider card with supporting text below as a natural lead-in to additional 171 | content. This content is a little bit longer.
172 |This is a wider card with supporting text below as a natural lead-in to additional 191 | content. This content is a little bit longer.
192 |