├── .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 | Python e Flask - GilcierWeb 9 | 10 | 12 | 13 | 14 | 15 | {% include 'views/partials/_header_top.html' %} 16 |
17 |
18 |
19 |

GilcierWeb

20 | 21 | {% block content %}{% endblock %} 22 | 23 |
24 |
25 |
26 | 27 | 29 | 31 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /templates/views/contacts/contact.html: -------------------------------------------------------------------------------- 1 | {% extends "application.html" %} 2 | 3 | {% block content %} 4 | 5 |

Contato

6 |
7 | {{ form.csrf_token }} 8 | 9 |
10 | {{ form.name.label }} 11 | {{ form.name(class='form-control') }} 12 | {% for error in form.name.errors %} 13 | [{{ error }}] 14 | {% endfor %} 15 |
16 | 17 |
18 | {{ form.email.label }} 19 | {{ form.email(class='form-control') }} 20 | {% for error in form.email.errors %} 21 | [{{ error }}] 22 | {% endfor %} 23 |
24 | 25 |
26 | {{ form.subject.label }} 27 | {{ form.subject(class='form-control') }} 28 | {% for error in form.subject.errors %} 29 | [{{ error }}] 30 | {% endfor %} 31 |
32 | 33 |
34 | {{ form.message.label }} 35 | {{ form.message(class='form-control') }} 36 | {% for error in form.message.errors %} 37 | [{{ error }}] 38 | {% endfor %} 39 |
40 | 41 | {{ form.submit(class='btn btn-success') }} 42 | 43 |
44 | 45 | {% endblock %} -------------------------------------------------------------------------------- /templates/views/home/index.html: -------------------------------------------------------------------------------- 1 | {% extends "application.html" %} 2 | {% block content %} 3 | 4 |
5 |
6 |

GilcierWeb

7 |

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 |
14 |
15 | 16 |
17 |
18 | 19 |
20 |
21 |
22 | 24 | Placeholder 25 | Thumbnail 26 | 27 |
28 |

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 |
31 |
32 | 33 | 34 |
35 | 9 mins 36 |
37 |
38 |
39 |
40 |
41 |
42 | 44 | Placeholder 45 | Thumbnail 46 | 47 |
48 |

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 |
51 |
52 | 53 | 54 |
55 | 9 mins 56 |
57 |
58 |
59 |
60 |
61 |
62 | 64 | Placeholder 65 | Thumbnail 66 | 67 |
68 |

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 |
71 |
72 | 73 | 74 |
75 | 9 mins 76 |
77 |
78 |
79 |
80 | 81 |
82 |
83 | 85 | Placeholder 86 | Thumbnail 87 | 88 |
89 |

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 |
92 |
93 | 94 | 95 |
96 | 9 mins 97 |
98 |
99 |
100 |
101 |
102 |
103 | 105 | Placeholder 106 | Thumbnail 107 | 108 |
109 |

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 |
112 |
113 | 114 | 115 |
116 | 9 mins 117 |
118 |
119 |
120 |
121 |
122 |
123 | 125 | Placeholder 126 | Thumbnail 127 | 128 |
129 |

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 |
132 |
133 | 134 | 135 |
136 | 9 mins 137 |
138 |
139 |
140 |
141 | 142 |
143 |
144 | 146 | Placeholder 147 | Thumbnail 148 | 149 |
150 |

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 |
153 |
154 | 155 | 156 |
157 | 9 mins 158 |
159 |
160 |
161 |
162 |
163 |
164 | 166 | Placeholder 167 | Thumbnail 168 | 169 |
170 |

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 |
173 |
174 | 175 | 176 |
177 | 9 mins 178 |
179 |
180 |
181 |
182 |
183 |
184 | 186 | Placeholder 187 | Thumbnail 188 | 189 |
190 |

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 |
193 |
194 | 195 | 196 |
197 | 9 mins 198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 | 206 | {% endblock %} -------------------------------------------------------------------------------- /templates/views/partials/_header_top.html: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------