Skip to content

Commit ec8a80e

Browse files
authored
Merge branch 'master' into Python-3.13-compatible---remove-CGI
2 parents 5c105c8 + 906bd5d commit ec8a80e

31 files changed

Lines changed: 387 additions & 230 deletions
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# This workflows will upload a Python Package using Twine when a release is created
2+
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3+
4+
name: Upload Python Package
5+
6+
on:
7+
release:
8+
types: [created]
9+
10+
jobs:
11+
deploy:
12+
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
- name: Set up Python
18+
uses: actions/setup-python@v2
19+
with:
20+
python-version: '3.x'
21+
- name: Install dependencies
22+
run: |
23+
python -m pip install --upgrade pip
24+
pip install setuptools wheel twine
25+
- name: Build and publish
26+
env:
27+
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
28+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
29+
run: |
30+
python setup.py sdist bdist_wheel
31+
twine upload dist/*

.github/workflows/tests.yaml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: Tests
2+
on:
3+
push:
4+
branches:
5+
- master
6+
- '*'
7+
pull_request:
8+
branches:
9+
- master
10+
11+
jobs:
12+
tests:
13+
name: ${{ matrix.name }}
14+
runs-on: ${{ matrix.os }}
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
include:
19+
- {name: '3.12', python: '3.12', os: ubuntu-latest, tox: py312}
20+
- {name: '3.11', python: '3.11', os: ubuntu-latest, tox: py311}
21+
- {name: '3.10', python: '3.10', os: ubuntu-latest, tox: py310}
22+
- {name: '3.9', python: '3.9', os: ubuntu-latest, tox: py39}
23+
- {name: '3.8', python: '3.8', os: ubuntu-latest, tox: py38}
24+
- {name: '3.7', python: '3.7', os: ubuntu-latest, tox: py37}
25+
- {name: '3.6', python: '3.6', os: ubuntu-20.04, tox: py36}
26+
services:
27+
postfix:
28+
image: lavr/docker-postfix
29+
env:
30+
SMTP_SERVER: smtp.gmail.com
31+
SMTP_PORT: 587
32+
SMTP_USERNAME: ${{ secrets.SMTP_TEST_GMAIL_USER }}
33+
SMTP_PASSWORD: ${{ secrets.SMTP_TEST_GMAIL_PASSWORD }}
34+
SERVER_HOSTNAME: python-emails-tests.github-ci.lavr.me
35+
ports:
36+
- 2525:25
37+
steps:
38+
- uses: actions/checkout@v2
39+
- uses: actions/setup-python@v2
40+
with:
41+
python-version: ${{ matrix.python }}
42+
- name: update pip
43+
run: |
44+
pip install -U wheel
45+
pip install -U setuptools
46+
python -m pip install -U pip
47+
- name: get pip cache dir
48+
id: pip-cache
49+
run: echo "::set-output name=dir::$(pip cache dir)"
50+
- name: cache pip
51+
uses: actions/cache@v1
52+
with:
53+
path: ${{ steps.pip-cache.outputs.dir }}
54+
key: pip|${{ runner.os }}|${{ matrix.python }}|${{ hashFiles('setup.py') }}|${{ hashFiles('requirements/*.txt') }}
55+
- run: pip install tox
56+
- name: run rests
57+
env:
58+
SMTP_TEST_SUBJECT_SUFFIX: "github-actions sha:${{ github.sha }} run_id:${{ github.run_id }}"
59+
SMTP_TEST_MAIL_FROM: python-emails-tests@lavr.me
60+
SMTP_TEST_MAIL_TO: python-emails-tests@lavr.me
61+
SMTP_TEST_SETS: LOCAL
62+
SMTP_TEST_LOCAL_WITHOUT_TLS: true
63+
SMTP_TEST_LOCAL_HOST: 127.0.0.1
64+
SMTP_TEST_LOCAL_PORT: 2525
65+
66+
SMTP_TEST_GMAIL_TO: python-emails-tests@lavr.me
67+
SMTP_TEST_GMAIL_USER: ${{ secrets.SMTP_TEST_GMAIL_USER }}
68+
SMTP_TEST_GMAIL_PASSWORD: ${{ secrets.SMTP_TEST_GMAIL_PASSWORD }}
69+
SMTP_TEST_GMAIL_WITH_TLS: true
70+
SMTP_TEST_GMAIL_HOST: smtp.gmail.com
71+
SMTP_TEST_GMAIL_PORT: 587
72+
SMTP_TEST_YAMAIL_TO: python.emails.test.2@yandex.ru
73+
SMTP_TEST_YAMAIL_FROM: python.emails.test.2@yandex.ru
74+
SMTP_TEST_YAMAIL_USER: python.emails.test.2
75+
SMTP_TEST_YAMAIL_PASSWORD: ${{ secrets.SMTP_TEST_YAMAIL_PASSWORD }}
76+
SMTP_TEST_YAMAIL_WITH_TLS: true
77+
SMTP_TEST_YAMAIL_HOST: smtp.yandex.ru
78+
SMTP_TEST_YAMAIL_PORT: 25
79+
run: tox -e ${{ matrix.tox }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@ nosetests.xml
3636
.project
3737
.pydevproject
3838
.idea
39+
40+
venv/
41+
.env

.pre-commit-config.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
repos:
2+
- repo: https://github.com/asottile/pyupgrade
3+
rev: v2.4.3
4+
hooks:
5+
- id: pyupgrade
6+
args: ["--py36-plus"]
7+
- repo: https://github.com/asottile/reorder_python_imports
8+
rev: v2.3.0
9+
hooks:
10+
- id: reorder-python-imports
11+
name: Reorder Python imports (src, tests)
12+
files: "^(?!examples/)"
13+
args: ["--application-directories", "src"]
14+
- repo: https://github.com/python/black
15+
rev: 19.10b0
16+
hooks:
17+
- id: black
18+
- repo: https://gitlab.com/pycqa/flake8
19+
rev: 3.8.2
20+
hooks:
21+
- id: flake8
22+
additional_dependencies:
23+
- flake8-bugbear
24+
- flake8-implicit-str-concat
25+
- repo: https://github.com/pre-commit/pre-commit-hooks
26+
rev: v3.1.0
27+
hooks:
28+
- id: check-byte-order-marker
29+
- id: trailing-whitespace
30+
- id: end-of-file-fixer
31+

.travis.yml

Lines changed: 0 additions & 36 deletions
This file was deleted.

README.rst

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,11 @@ Flask extension: `flask-emails <https://github.com/lavr/flask-emails>`_
3737
|
3838
|
3939
40-
.. image:: https://travis-ci.org/lavr/python-emails.png?branch=master
41-
:target: https://travis-ci.org/lavr/python-emails
40+
.. image:: https://github.com/lavr/python-emails/workflows/Tests/badge.svg?branch=master
41+
:target: https://github.com/lavr/python-emails/actions?query=workflow%3ATests
4242

4343
.. image:: https://img.shields.io/pypi/v/emails.svg
4444
:target: https://pypi.python.org/pypi/emails
4545

46-
.. image:: http://allmychanges.com/p/python/emails/badge/
47-
:target: http://allmychanges.com/p/python/emails/?utm_source=badge
48-
4946
.. image:: https://coveralls.io/repos/lavr/python-emails/badge.svg?branch=master
5047
:target: https://coveralls.io/r/lavr/python-emails?branch=master

emails/backend/smtp/backend.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class SMTPBackend(object):
2626
connection_ssl_cls = SMTPClientWithResponse_SSL
2727
response_cls = SMTPResponse
2828

29-
def __init__(self, ssl=False, fail_silently=True, **kwargs):
29+
def __init__(self, ssl=False, fail_silently=True, mail_options=None, **kwargs):
3030

3131
self.smtp_cls = ssl and self.connection_ssl_cls or self.connection_cls
3232

@@ -46,6 +46,7 @@ def __init__(self, ssl=False, fail_silently=True, **kwargs):
4646
self.host = kwargs.get('host')
4747
self.port = kwargs.get('port')
4848
self.fail_silently = fail_silently
49+
self.mail_options = mail_options or []
4950

5051
self._client = None
5152

@@ -90,10 +91,14 @@ def _send(self, **kwargs):
9091
response = None
9192
try:
9293
client = self.get_client()
93-
except IOError as exc:
94-
response = self.make_response(exception=SMTPConnectNetworkError.from_ioerror(exc))
9594
except smtplib.SMTPException as exc:
9695
response = self.make_response(exception=exc)
96+
if not self.fail_silently:
97+
raise
98+
except IOError as exc:
99+
response = self.make_response(exception=SMTPConnectNetworkError.from_ioerror(exc))
100+
if not self.fail_silently:
101+
raise
97102

98103
if response:
99104
if not self.fail_silently:
@@ -114,8 +119,8 @@ def sendmail(self, from_addr, to_addrs, msg, mail_options=None, rcpt_options=Non
114119

115120
response = send(from_addr=from_addr,
116121
to_addrs=to_addrs,
117-
msg=msg.as_string(),
118-
mail_options=mail_options,
122+
msg=msg.as_bytes(),
123+
mail_options=mail_options or self.mail_options,
119124
rcpt_options=rcpt_options)
120125

121126
if not self.fail_silently:

emails/backend/smtp/client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def __init__(self, parent, **kwargs):
2727

2828
self.initialize()
2929

30+
3031
def initialize(self):
3132
if not self._initialized:
3233
self.set_debuglevel(self.debug)

emails/compat/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,10 @@ def formataddr(pair):
160160
Does not encode non-ascii realname.
161161
162162
Python3 email.utils.formataddr do encode realname.
163+
164+
TODO: switch to email.headerregistry.AddressHeader ?
163165
"""
166+
164167
name, address = pair
165168
if name:
166169
quotes = ''

emails/loader/helpers.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# encoding: utf-8
22
from __future__ import unicode_literals
33
__all__ = ['guess_charset', 'fix_content_type']
4+
from email.message import Message
5+
46

57
import re
68
import warnings
@@ -52,7 +54,7 @@ class ReRules:
5254
re_meta = b"(?i)(?<=<meta).*?(?=>)"
5355
re_is_http_equiv = b"http-equiv=\"?'?content-type\"?'?"
5456
re_parse_http_equiv = b"content=\"?'?([^\"'>]+)"
55-
re_charset = b"charset=\"?'?([\w-]+)\"?'?"
57+
re_charset = b"charset=\"?'?([\\w-]+)\"?'?"
5658

5759
def __init__(self, conv=None):
5860
if conv is None:
@@ -93,6 +95,10 @@ def guess_charset(headers, html):
9395
if content_type:
9496
_, params = parse_header(content_type)
9597
r = params.get('charset', None)
98+
msg = Message()
99+
msg.add_header('content-type', content_type)
100+
r = msg.get_param('charset')
101+
96102
if r:
97103
return r
98104

0 commit comments

Comments
 (0)