Надсилання пошти через sendmail з python


77

Якщо я хочу надсилати пошту не через SMTP, а скоріше через sendmail, чи існує бібліотека для python, яка інкапсулює цей процес?

А ще краще, чи існує хороша бібліотека, яка абстрагує весь вибір 'sendmail -versus- smtp'?

Я буду запускати цей скрипт на купу хостів Unix, лише деякі з яких слухають на localhost: 25; деякі з них є частиною вбудованих систем і не можуть бути налаштовані на прийняття SMTP.

Як частина належної практики, я б дуже хотів, щоб бібліотека сама піклувалась про вразливості введення заголовка - тому просто скидання рядка popen('/usr/bin/sendmail', 'w')в трохи ближче до металу, ніж я хотів би.

Якщо відповідь: "піди, напиши бібліотеку", нехай буде ;-)

Відповіді:


126

Введення заголовка не є фактором того, як ви надсилаєте пошту, це фактор того, як ви будуєте пошту. Перевірте пакет електронної пошти, побудуйте пошту з цього, серіалізуйте його та надішліть за /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. Це зупиняє .передчасне припинення електронної пошти жодного повідомлення у вашому повідомленні.
Robie Basak

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рішень у стилі. Гірше, причиною було уникнення таких речей, як уразливість введення заголовка. Якщо користувач надає адресу з або на адресу, цей код вразливий до атак введення заголовка. Це саме те, чого вони не хотіли.
Джим,

6
@Jim так, вони спеціально відредагували цю частину після того, як була дана моя відповідь (перевірте дати редагування), у відповідь на мою відповідь, я гадаю.
Пітер,

@Pieter, якщо мені потрібно надіслати вкладення?
Hariom Singh

12

Відповідь Джима для мене не спрацювала в 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

1
+1 для Marrow Mailer. Я спробував це, і це дуже полегшує надсилання пошти через smpt, sendmail тощо, а також забезпечує дуже хорошу перевірку. Оскільки Marrow Mailer - це "хороша бібліотека, яка абстрагує весь вибір" sendmail -versus- smtp "", я вважаю, що це найкраще відповідає на вихідне питання.
tjklemz

3

Досить поширеним є просто використання команди sendmail з Python за допомогою os.popen

Особисто для сценаріїв, які я не писав сам, я думаю, що просто використання протоколу SMTP є кращим, оскільки для цього не потрібно встановлювати, скажімо, клон sendmail для запуску у вікнах.

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


1
SMTP не працює на ~ nix-ящиках, використовуючи такі речі, як DMA , який забезпечує sendmail, але не слухає порт 25 ...
Герт ван ден Берг,

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. А деякі користувачі не хочуть відкривати порт 21 навіть на локальному хості.
народження дитини

-7

Найпростіша відповідь є smtplib, ви можете знайти документи на нього тут .

Все, що вам потрібно зробити, це налаштувати ваш локальний sendmail, щоб він приймав підключення від localhost, що він, мабуть, вже робить за замовчуванням. Звичайно, ви все ще використовуєте SMTP для передачі, але це локальний sendmail, який в основному такий самий, як використання інструменту командного рядка.


7
Питання говорить "Якщо я хочу надсилати пошту не через SMTP, а швидше за допомогою sendmail ..."
S19N

1
Ваша програма затримається у разі відсутності підключення або затримки SMTP-сервера. За допомогою sendmail ви передаєте повідомлення на MTA, і ваша програма продовжується.
Денис Барменков
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.