通过sendmail从python发送邮件


77

如果我不想通过SMTP而是通过sendmail发送邮件,是否有用于封装此过程的python库?

更好的是,是否有一个好的库可以抽象整个“ sendmail -versus- smtp”选择?

我将在大量的Unix主机上运行此脚本,其中只有一些在localhost:25上侦听;其中一些是嵌入式系统的一部分,不能设置为接受SMTP。

作为优良作法的一部分,我真的很想让库自己解决标头注入漏洞—因此,仅将字符串转储popen('/usr/bin/sendmail', 'w')到比我想要的更接近金属的地方。

如果答案是“去写一个库”,那就去吧;-)

Answers:


125

标头注入不是发送邮件的方式,而是构建邮件的方式。检查电子邮件程序包,使用该程序包构造邮件,对其进行序列化,然后/usr/sbin/sendmail使用子流程模块将其发送给:

import sys
from email.mime.text import MIMEText
from subprocess import Popen, PIPE


msg = MIMEText("Here is the body of my message")
msg["From"] = "me@example.com"
msg["To"] = "you@example.com"
msg["Subject"] = "This is the subject."
p = Popen(["/usr/sbin/sendmail", "-t", "-oi"], stdin=PIPE)
# Both Python 2.X and 3.X
p.communicate(msg.as_bytes() if sys.version_info >= (3,0) else msg.as_string()) 

# Python 2.X
p.communicate(msg.as_string())

# Python 3.X
p.communicate(msg.as_bytes())

完善。我的概念性问题是将电子邮件的构造和发送分开。谢谢!
Nate

3
很好,经过5年的回答,今天对我有帮助:)
彼得

14
您还应该使用-oi参数sendmail。这样可以阻止.消息中的单个消息过早地终止电子邮件。
罗比·巴萨克

26
python3用户应使用.as_bytes()代替as_string()
ov7a

我对...感到困惑-oi-o看起来像是用于设置处理选项的,-i看起来只适用于接收邮件...
DylanYoung

36

这是一个简单的python函数,它使用unix sendmail传递邮件。

def sendMail():
    sendmail_location = "/usr/sbin/sendmail" # sendmail location
    p = os.popen("%s -t" % sendmail_location, "w")
    p.write("From: %s\n" % "from@somewhere.com")
    p.write("To: %s\n" % "to@somewhereelse.com")
    p.write("Subject: thesubject\n")
    p.write("\n") # blank line separating headers from body
    p.write("body of the mail")
    status = p.close()
    if status != 0:
           print "Sendmail exit status", status

2
他们特别表示,他们不想要popen样式解决方案。更糟糕的是,给出的原因是为了避免诸如标头注入漏洞之类的事情。如果用户提供发件人或收件人地址,则此代码容易受到标头注入攻击。这正是他们所不想要的。
吉姆(Jim)

6
@Jim是的,他们回答了我的回答,然后在给出我的回答(检查编辑日期)后专门编辑了该部分。
Pieter

@Pieter是否必须发送附件?
哈里安姆·辛格

12

Jim的答案在Python 3.4中对我不起作用。我不得不添加一个额外的universal_newlines=True参数subrocess.Popen()

from email.mime.text import MIMEText
from subprocess import Popen, PIPE

msg = MIMEText("Here is the body of my message")
msg["From"] = "me@example.com"
msg["To"] = "you@example.com"
msg["Subject"] = "This is the subject."
p = Popen(["/usr/sbin/sendmail", "-t", "-oi"], stdin=PIPE, universal_newlines=True)
p.communicate(msg.as_string())

没有universal_newlines=True我得到

TypeError: 'str' does not support the buffer interface

5

这个问题很老,但是值得一提的是,自从询问此消息开始,就有一个名为Marrow Mailer(以前称为TurboMail)的消息构建和电子邮件传递系统。

现在正在移植以支持Python 3,并已作为Marrow套件的一部分进行了更新。


一年后,turboMail链接无法使用
TankorSmash 2012年

1
骨髓邮递员+1。我试用了它,它使通过smpt,sendmail等发送邮件变得非常容易,并且还提供了很好的验证。因为Marrow Mailer是“一个很好的库,它抽象了整个'sendmail -versus- smtp'选项。
tjklemz 2012年

3

仅使用os.popen从Python使用sendmail命令是很常见的

就个人而言,对于我自己没有编写的脚本,我认为仅使用SMTP协议会更好,因为它不需要安装说sendmail克隆即可在Windows上运行。

https://docs.python.org/library/smtplib.html


1
SMTP在使用DMA之类的〜nix盒上不起作用,它提供sendmail,但不能在端口25上侦听...
Gert van den Berg

3

Python 3.5以上版本:

import subprocess
from email.message import EmailMessage

def sendEmail(from_addr, to_addrs, msg_subject, msg_body):
    msg = EmailMessage()
    msg.set_content(msg_body)
    msg['From'] = from_addr
    msg['To'] = to_addrs
    msg['Subject'] = msg_subject

    sendmail_location = "/usr/sbin/sendmail"
    subprocess.run([sendmail_location, "-t", "-oi"], input=msg.as_bytes())

-2

我只是在寻找同样的东西,并在Python网站上找到了一个很好的例子:http : //docs.python.org/2/library/email-examples.html

从提到的站点:

# Import smtplib for the actual sending function
import smtplib

# Import the email modules we'll need
from email.mime.text import MIMEText

# Open a plain text file for reading.  For this example, assume that
# the text file contains only ASCII characters.
fp = open(textfile, 'rb')
# Create a text/plain message
msg = MIMEText(fp.read())
fp.close()

# me == the sender's email address
# you == the recipient's email address
msg['Subject'] = 'The contents of %s' % textfile
msg['From'] = me
msg['To'] = you

# Send the message via our own SMTP server, but don't include the
# envelope header.
s = smtplib.SMTP('localhost')
s.sendmail(me, [you], msg.as_string())
s.quit()

请注意,这要求您正确设置sendmail / mailx才能接受“ localhost”上的连接。默认情况下,这适用于我的Mac,Ubuntu和Redhat服务器,但是您可能要仔细检查是否遇到任何问题。


这仍localhost通过SMTP协议使用。而且有些用户不想甚至只在localhost上就打开端口21。
mbirth '17

-7

最简单的答案是smtplib,您可以在此处找到文档。

您需要做的就是将本地sendmail配置为接受来自localhost的连接,默认情况下它可能已经这样做。当然,您仍然使用SMTP进行传输,但这是本地sendmail,与使用命令行工具基本相同。


7
问题说:“如果我不想通过SMTP发送邮件,而是通过sendmail ...”
2012年

1
万一没有连接或SMTP服务器滞后,您的程序将延迟。使用sendmail可以将消息传递到MTA,然后程序继续。
Denis Barmenkov 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.