Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
db4120bf
Kaydet (Commit)
db4120bf
authored
Tem 03, 2011
tarafından
R David Murray
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Sade Fark
merge #12147: make send_message correctly handle Sender and Resent- headers.
üst
020436b0
ac4e5abc
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
172 additions
and
22 deletions
+172
-22
smtplib.rst
Doc/library/smtplib.rst
+19
-8
smtplib.py
Lib/smtplib.py
+39
-13
test_smtplib.py
Lib/test/test_smtplib.py
+110
-1
ACKS
Misc/ACKS
+1
-0
NEWS
Misc/NEWS
+3
-0
No files found.
Doc/library/smtplib.rst
Dosyayı görüntüle @
db4120bf
...
@@ -348,21 +348,32 @@ An :class:`SMTP` instance has the following methods:
...
@@ -348,21 +348,32 @@ An :class:`SMTP` instance has the following methods:
.. versionchanged:: 3.2 *msg* may be a byte string.
.. versionchanged:: 3.2 *msg* may be a byte string.
.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=[], rcpt_options=[])
.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, \
mail_options=[], rcpt_options=[])
This is a convenience method for calling :meth:`sendmail` with the message
This is a convenience method for calling :meth:`sendmail` with the message
represented by an :class:`email.message.Message` object. The arguments have
represented by an :class:`email.message.Message` object. The arguments have
the same meaning as for :meth:`sendmail`, except that *msg* is a ``Message``
the same meaning as for :meth:`sendmail`, except that *msg* is a ``Message``
object.
object.
If *from_addr* is ``None``, ``send_message`` sets its value to the value of
If *from_addr* is ``None`` or *to_addrs* is ``None``, ``send_message`` fills
the :mailheader:`From` header from *msg*. If *to_addrs* is ``None``,
those arguments with addresses extracted from the headers of *msg* as
``send_message`` combines the values (if any) of the :mailheader:`To`,
specified in :rfc:`2822`\: *from_addr* is set to the :mailheader:`Sender`
:mailheader:`CC`, and :mailheader:`Bcc` fields from *msg*. Regardless of
field if it is present, and otherwise to the :mailheader:`From` field.
the values of *from_addr* and *to_addrs*, ``send_message`` deletes any Bcc
*to_adresses* combines the values (if any) of the :mailheader:`To`,
field from *msg*. It then serializes *msg* using
:mailheader:`Cc`, and :mailheader:`Bcc` fields from *msg*. If exactly one
set of :mailheader:`Resent-*` headers appear in the message, the regular
headers are ignored and the :mailheader:`Resent-*` headers are used instead.
If the message contains more than one set of :mailheader:`Resent-*` headers,
a :exc:`ValueError` is raised, since there is no way to unambiguously detect
the most recent set of :mailheader:`Resent-` headers.
``send_message`` serializes *msg* using
:class:`~email.generator.BytesGenerator` with ``\r\n`` as the *linesep*, and
:class:`~email.generator.BytesGenerator` with ``\r\n`` as the *linesep*, and
calls :meth:`sendmail` to transmit the resulting message.
calls :meth:`sendmail` to transmit the resulting message. Regardless of the
values of *from_addr* and *to_addrs*, ``send_message`` does not transmit any
:mailheader:`Bcc` or :mailheader:`Resent-Bcc` headers that may appear
in *msg*.
.. versionadded:: 3.2
.. versionadded:: 3.2
...
...
Lib/smtplib.py
100755 → 100644
Dosyayı görüntüle @
db4120bf
...
@@ -49,6 +49,7 @@ import email.message
...
@@ -49,6 +49,7 @@ import email.message
import
email.generator
import
email.generator
import
base64
import
base64
import
hmac
import
hmac
import
copy
from
email.base64mime
import
body_encode
as
encode_base64
from
email.base64mime
import
body_encode
as
encode_base64
from
sys
import
stderr
from
sys
import
stderr
...
@@ -676,7 +677,7 @@ class SMTP:
...
@@ -676,7 +677,7 @@ class SMTP:
msg may be a string containing characters in the ASCII range, or a byte
msg may be a string containing characters in the ASCII range, or a byte
string. A string is encoded to bytes using the ascii codec, and lone
string. A string is encoded to bytes using the ascii codec, and lone
\
r
and
\n
characters are converted to
\r
\n
characters.
\
\
r and
\\
n characters are converted to
\\
r
\
\
n characters.
If there has been no previous EHLO or HELO command this session, this
If there has been no previous EHLO or HELO command this session, this
method tries ESMTP EHLO first. If the server does ESMTP, message size
method tries ESMTP EHLO first. If the server does ESMTP, message size
...
@@ -759,24 +760,49 @@ class SMTP:
...
@@ -759,24 +760,49 @@ class SMTP:
"""Converts message to a bytestring and passes it to sendmail.
"""Converts message to a bytestring and passes it to sendmail.
The arguments are as for sendmail, except that msg is an
The arguments are as for sendmail, except that msg is an
email.message.Message object. If from_addr is None, the from_addr is
email.message.Message object. If from_addr is None or to_addrs is
taken from the 'From' header of the Message. If to_addrs is None, its
None, these arguments are taken from the headers of the Message as
value is composed from the addresses listed in the 'To', 'CC', and
described in RFC 2822 (a ValueError is raised if there is more than
'Bcc' fields. Regardless of the values of from_addr and to_addr, any
one set of 'Resent-' headers). Regardless of the values of from_addr and
Bcc field in the Message object is deleted. The Message object is then
to_addr, any Bcc field (or Resent-Bcc field, when the Message is a
serialized using email.generator.BytesGenerator and sendmail is called
resent) of the Message object won't be transmitted. The Message
to transmit the message.
object is then serialized using email.generator.BytesGenerator and
sendmail is called to transmit the message.
"""
"""
# 'Resent-Date' is a mandatory field if the Message is resent (RFC 2822
# Section 3.6.6). In such a case, we use the 'Resent-*' fields. However,
# if there is more than one 'Resent-' block there's no way to
# unambiguously determine which one is the most recent in all cases,
# so rather than guess we raise a ValueError in that case.
#
# TODO implement heuristics to guess the correct Resent-* block with an
# option allowing the user to enable the heuristics. (It should be
# possible to guess correctly almost all of the time.)
resent
=
msg
.
get_all
(
'Resent-Date'
)
if
resent
is
None
:
header_prefix
=
''
elif
len
(
resent
)
==
1
:
header_prefix
=
'Resent-'
else
:
raise
ValueError
(
"message has more than one 'Resent-' header block"
)
if
from_addr
is
None
:
if
from_addr
is
None
:
from_addr
=
msg
[
'From'
]
# Prefer the sender field per RFC 2822:3.6.2.
from_addr
=
(
msg
[
header_prefix
+
'Sender'
]
if
(
header_prefix
+
'Sender'
)
in
msg
else
msg
[
header_prefix
+
'From'
])
if
to_addrs
is
None
:
if
to_addrs
is
None
:
addr_fields
=
[
f
for
f
in
(
msg
[
'To'
],
msg
[
'Bcc'
],
msg
[
'CC'
])
addr_fields
=
[
f
for
f
in
(
msg
[
header_prefix
+
'To'
],
if
f
is
not
None
]
msg
[
header_prefix
+
'Bcc'
],
msg
[
header_prefix
+
'Cc'
])
if
f
is
not
None
]
to_addrs
=
[
a
[
1
]
for
a
in
email
.
utils
.
getaddresses
(
addr_fields
)]
to_addrs
=
[
a
[
1
]
for
a
in
email
.
utils
.
getaddresses
(
addr_fields
)]
del
msg
[
'Bcc'
]
# Make a local copy so we can delete the bcc headers.
msg_copy
=
copy
.
copy
(
msg
)
del
msg_copy
[
'Bcc'
]
del
msg_copy
[
'Resent-Bcc'
]
with
io
.
BytesIO
()
as
bytesmsg
:
with
io
.
BytesIO
()
as
bytesmsg
:
g
=
email
.
generator
.
BytesGenerator
(
bytesmsg
)
g
=
email
.
generator
.
BytesGenerator
(
bytesmsg
)
g
.
flatten
(
msg
,
linesep
=
'
\r\n
'
)
g
.
flatten
(
msg
_copy
,
linesep
=
'
\r\n
'
)
flatmsg
=
bytesmsg
.
getvalue
()
flatmsg
=
bytesmsg
.
getvalue
()
return
self
.
sendmail
(
from_addr
,
to_addrs
,
flatmsg
,
mail_options
,
return
self
.
sendmail
(
from_addr
,
to_addrs
,
flatmsg
,
mail_options
,
rcpt_options
)
rcpt_options
)
...
...
Lib/test/test_smtplib.py
Dosyayı görüntüle @
db4120bf
...
@@ -320,13 +320,16 @@ class DebuggingServerTests(unittest.TestCase):
...
@@ -320,13 +320,16 @@ class DebuggingServerTests(unittest.TestCase):
# XXX (see comment in testSend)
# XXX (see comment in testSend)
time
.
sleep
(
0.01
)
time
.
sleep
(
0.01
)
smtp
.
quit
()
smtp
.
quit
()
# make sure the Bcc header is still in the message.
self
.
assertEqual
(
m
[
'Bcc'
],
'John Root <root@localhost>, "Dinsdale" '
'<warped@silly.walks.com>'
)
self
.
client_evt
.
set
()
self
.
client_evt
.
set
()
self
.
serv_evt
.
wait
()
self
.
serv_evt
.
wait
()
self
.
output
.
flush
()
self
.
output
.
flush
()
# Add the X-Peer header that DebuggingServer adds
# Add the X-Peer header that DebuggingServer adds
m
[
'X-Peer'
]
=
socket
.
gethostbyname
(
'localhost'
)
m
[
'X-Peer'
]
=
socket
.
gethostbyname
(
'localhost'
)
# The Bcc header
is deleted before serialization
.
# The Bcc header
should not be transmitted
.
del
m
[
'Bcc'
]
del
m
[
'Bcc'
]
mexpect
=
'
%
s
%
s
\n
%
s'
%
(
MSG_BEGIN
,
m
.
as_string
(),
MSG_END
)
mexpect
=
'
%
s
%
s
\n
%
s'
%
(
MSG_BEGIN
,
m
.
as_string
(),
MSG_END
)
self
.
assertEqual
(
self
.
output
.
getvalue
(),
mexpect
)
self
.
assertEqual
(
self
.
output
.
getvalue
(),
mexpect
)
...
@@ -365,6 +368,112 @@ class DebuggingServerTests(unittest.TestCase):
...
@@ -365,6 +368,112 @@ class DebuggingServerTests(unittest.TestCase):
re
.
MULTILINE
)
re
.
MULTILINE
)
self
.
assertRegex
(
debugout
,
to_addr
)
self
.
assertRegex
(
debugout
,
to_addr
)
def
testSendMessageWithSpecifiedAddresses
(
self
):
# Make sure addresses specified in call override those in message.
m
=
email
.
mime
.
text
.
MIMEText
(
'A test message'
)
m
[
'From'
]
=
'foo@bar.com'
m
[
'To'
]
=
'John, Dinsdale'
smtp
=
smtplib
.
SMTP
(
HOST
,
self
.
port
,
local_hostname
=
'localhost'
,
timeout
=
3
)
smtp
.
send_message
(
m
,
from_addr
=
'joe@example.com'
,
to_addrs
=
'foo@example.net'
)
# XXX (see comment in testSend)
time
.
sleep
(
0.01
)
smtp
.
quit
()
self
.
client_evt
.
set
()
self
.
serv_evt
.
wait
()
self
.
output
.
flush
()
# Add the X-Peer header that DebuggingServer adds
m
[
'X-Peer'
]
=
socket
.
gethostbyname
(
'localhost'
)
mexpect
=
'
%
s
%
s
\n
%
s'
%
(
MSG_BEGIN
,
m
.
as_string
(),
MSG_END
)
self
.
assertEqual
(
self
.
output
.
getvalue
(),
mexpect
)
debugout
=
smtpd
.
DEBUGSTREAM
.
getvalue
()
sender
=
re
.
compile
(
"^sender: joe@example.com$"
,
re
.
MULTILINE
)
self
.
assertRegex
(
debugout
,
sender
)
for
addr
in
(
'John'
,
'Dinsdale'
):
to_addr
=
re
.
compile
(
r"^recips: .*'{}'.*$"
.
format
(
addr
),
re
.
MULTILINE
)
self
.
assertNotRegex
(
debugout
,
to_addr
)
recip
=
re
.
compile
(
r"^recips: .*'foo@example.net'.*$"
,
re
.
MULTILINE
)
self
.
assertRegex
(
debugout
,
recip
)
def
testSendMessageWithMultipleFrom
(
self
):
# Sender overrides To
m
=
email
.
mime
.
text
.
MIMEText
(
'A test message'
)
m
[
'From'
]
=
'Bernard, Bianca'
m
[
'Sender'
]
=
'the_rescuers@Rescue-Aid-Society.com'
m
[
'To'
]
=
'John, Dinsdale'
smtp
=
smtplib
.
SMTP
(
HOST
,
self
.
port
,
local_hostname
=
'localhost'
,
timeout
=
3
)
smtp
.
send_message
(
m
)
# XXX (see comment in testSend)
time
.
sleep
(
0.01
)
smtp
.
quit
()
self
.
client_evt
.
set
()
self
.
serv_evt
.
wait
()
self
.
output
.
flush
()
# Add the X-Peer header that DebuggingServer adds
m
[
'X-Peer'
]
=
socket
.
gethostbyname
(
'localhost'
)
mexpect
=
'
%
s
%
s
\n
%
s'
%
(
MSG_BEGIN
,
m
.
as_string
(),
MSG_END
)
self
.
assertEqual
(
self
.
output
.
getvalue
(),
mexpect
)
debugout
=
smtpd
.
DEBUGSTREAM
.
getvalue
()
sender
=
re
.
compile
(
"^sender: the_rescuers@Rescue-Aid-Society.com$"
,
re
.
MULTILINE
)
self
.
assertRegex
(
debugout
,
sender
)
for
addr
in
(
'John'
,
'Dinsdale'
):
to_addr
=
re
.
compile
(
r"^recips: .*'{}'.*$"
.
format
(
addr
),
re
.
MULTILINE
)
self
.
assertRegex
(
debugout
,
to_addr
)
def
testSendMessageResent
(
self
):
m
=
email
.
mime
.
text
.
MIMEText
(
'A test message'
)
m
[
'From'
]
=
'foo@bar.com'
m
[
'To'
]
=
'John'
m
[
'CC'
]
=
'Sally, Fred'
m
[
'Bcc'
]
=
'John Root <root@localhost>, "Dinsdale" <warped@silly.walks.com>'
m
[
'Resent-Date'
]
=
'Thu, 1 Jan 1970 17:42:00 +0000'
m
[
'Resent-From'
]
=
'holy@grail.net'
m
[
'Resent-To'
]
=
'Martha <my_mom@great.cooker.com>, Jeff'
m
[
'Resent-Bcc'
]
=
'doe@losthope.net'
smtp
=
smtplib
.
SMTP
(
HOST
,
self
.
port
,
local_hostname
=
'localhost'
,
timeout
=
3
)
smtp
.
send_message
(
m
)
# XXX (see comment in testSend)
time
.
sleep
(
0.01
)
smtp
.
quit
()
self
.
client_evt
.
set
()
self
.
serv_evt
.
wait
()
self
.
output
.
flush
()
# The Resent-Bcc headers are deleted before serialization.
del
m
[
'Bcc'
]
del
m
[
'Resent-Bcc'
]
# Add the X-Peer header that DebuggingServer adds
m
[
'X-Peer'
]
=
socket
.
gethostbyname
(
'localhost'
)
mexpect
=
'
%
s
%
s
\n
%
s'
%
(
MSG_BEGIN
,
m
.
as_string
(),
MSG_END
)
self
.
assertEqual
(
self
.
output
.
getvalue
(),
mexpect
)
debugout
=
smtpd
.
DEBUGSTREAM
.
getvalue
()
sender
=
re
.
compile
(
"^sender: holy@grail.net$"
,
re
.
MULTILINE
)
self
.
assertRegex
(
debugout
,
sender
)
for
addr
in
(
'my_mom@great.cooker.com'
,
'Jeff'
,
'doe@losthope.net'
):
to_addr
=
re
.
compile
(
r"^recips: .*'{}'.*$"
.
format
(
addr
),
re
.
MULTILINE
)
self
.
assertRegex
(
debugout
,
to_addr
)
def
testSendMessageMultipleResentRaises
(
self
):
m
=
email
.
mime
.
text
.
MIMEText
(
'A test message'
)
m
[
'From'
]
=
'foo@bar.com'
m
[
'To'
]
=
'John'
m
[
'CC'
]
=
'Sally, Fred'
m
[
'Bcc'
]
=
'John Root <root@localhost>, "Dinsdale" <warped@silly.walks.com>'
m
[
'Resent-Date'
]
=
'Thu, 1 Jan 1970 17:42:00 +0000'
m
[
'Resent-From'
]
=
'holy@grail.net'
m
[
'Resent-To'
]
=
'Martha <my_mom@great.cooker.com>, Jeff'
m
[
'Resent-Bcc'
]
=
'doe@losthope.net'
m
[
'Resent-Date'
]
=
'Thu, 2 Jan 1970 17:42:00 +0000'
m
[
'Resent-To'
]
=
'holy@grail.net'
m
[
'Resent-From'
]
=
'Martha <my_mom@great.cooker.com>, Jeff'
smtp
=
smtplib
.
SMTP
(
HOST
,
self
.
port
,
local_hostname
=
'localhost'
,
timeout
=
3
)
with
self
.
assertRaises
(
ValueError
):
smtp
.
send_message
(
m
)
smtp
.
close
()
class
NonConnectingTests
(
unittest
.
TestCase
):
class
NonConnectingTests
(
unittest
.
TestCase
):
...
...
Misc/ACKS
Dosyayı görüntüle @
db4120bf
...
@@ -278,6 +278,7 @@ Ben Escoto
...
@@ -278,6 +278,7 @@ Ben Escoto
Andy Eskilsson
Andy Eskilsson
André Espaze
André Espaze
Stefan Esser
Stefan Esser
Nicolas Estibals
Stephen D Evans
Stephen D Evans
Carey Evans
Carey Evans
Tim Everett
Tim Everett
...
...
Misc/NEWS
Dosyayı görüntüle @
db4120bf
...
@@ -203,6 +203,9 @@ Core and Builtins
...
@@ -203,6 +203,9 @@ Core and Builtins
Library
Library
-------
-------
- Issue #12147: Adjust the new-in-3.2 smtplib.send_message method for better
conformance to the RFCs: correctly handle Sender and Resent- headers.
- Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by
- Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by
the garbage collector while the Heap lock is held.
the garbage collector while the Heap lock is held.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment