Arun Persaud suggested IMAP as an additional email delivery mechanism.
The benefit of using IMAP over SMTP is that you can set the target
mailbox directly (instead of filtering the incoming mail with procmail
or a similar external tool). This commit restructures the 'send'
configuration to support IMAP output with a configurable mailbox.
That means you can do something like:
[DEFAULT]
email-protocol: imap
imap-auth: True
imap-username: myname
imap-password: mypass
imap-server: imap.yourisp.net
imap-port: 993
imap-ssl: True
[feed.rss2email]
url = http://www.allthingsrss.com/rss2email/feed/
imap-mailbox = rss2email
[feed.xkcd]
url = http://xkcd.com/atom.xml
imap-mailbox = xkcd
For non-IMAP users, note that the boolean `use-smtp` configuration
variable is gone, replaced by the more flexible `email-protocol`.
You'll want to replace:
use-smtp = False
with:
email-protocol = sendmail
and replace:
use-smtp = True
with:
email-protocol = smtp
Signed-off-by: W. Trevor King <wking@tremily.us>
('body-width', str(0)),
### Mailing
+ # Select protocol from: sendmail, smtp, imap
+ ('email-protocol', 'sendmail'),
# True: Use SMTP_SERVER to send mail.
- # False: Use sendmail (or compatible) to send mail.
- ('use-smtp', str(False)),
+ # Sendmail (or compatible) configuration
('sendmail', '/usr/sbin/sendmail'), # Path to sendmail (or compatible)
- ('smtp-server', 'smtp.yourisp.net:25'), ('smtp-auth', str(False)), # set to True to use SMTP AUTH
+ # SMTP configuration
+ ('smtp-auth', str(False)), # set to True to use SMTP AUTH
('smtp-username', 'username'), # username for SMTP AUTH
('smtp-password', 'password'), # password for SMTP AUTH
+ ('smtp-server', 'smtp.yourisp.net:25'),
('smtp-ssl', str(False)), # Connect to the SMTP server using SSL
+ # IMAP configuration
+ ('imap-auth', str(False)), # set to True to use IMAP auth.
+ ('imap-username', 'username'), # username for IMAP authentication
+ ('imap-password', 'password'), # password for IMAP authentication
+ ('imap-server', 'imap.yourisp.net'),
+ ('imap-port', str(143)),
+ ('imap-ssl', str(False)), # connect to the IMAP server using SSL
+ ('imap-mailbox', 'INBOX'), # where we should store new messages
### Miscellaneous
# Verbosity (one of 'error', 'warning', 'info', or 'debug').
from email.mime.text import MIMEText as _MIMEText
from email.utils import formataddr as _formataddr
from email.utils import parseaddr as _parseaddr
+import imaplib as _imaplib
import io as _io
import smtplib as _smtplib
import subprocess as _subprocess
import sys as _sys
+import time as _time
from . import LOG as _LOG
from . import config as _config
smtp.send_message(message, sender, [recipient])
smtp.quit()
+def imap_send(message, config=None, section='DEFAULT'):
+ if config is None:
+ config = _config.CONFIG
+ server = config.get(section, 'imap-server')
+ port = config.getint(section, 'imap-port')
+ _LOG.debug('sending message to {}:{}'.format(server, port))
+ ssl = config.getboolean(section, 'imap-ssl')
+ if ssl:
+ imap = _imaplib.IMAP4_SSL(server, port)
+ else:
+ imap = _imaplib.IMAP4(server, port)
+ try:
+ imap.connect(server)
+ except KeyboardInterrupt:
+ raise
+ except Exception as e:
+ raise _error.IMAPConnectionError(server=server) from e
+ try:
+ if config.getboolean(section, 'imap-auth'):
+ username = config.get(section, 'imap-username')
+ password = config.get(section, 'imap-password')
+ try:
+ if not ssl:
+ imap.starttls()
+ imap.login(username, password)
+ except KeyboardInterrupt:
+ raise
+ except Exception as e:
+ raise _error.IMAPAuthenticationError(
+ server=server, username=username)
+ mailbox = config.get(section, 'imap-mailbox')
+ date = _imaplib.Time2Internaldate(_time.localtime())
+ message_bytes = _flatten(message)
+ imap.append(mailbox, None, date, message_bytes)
+ finally:
+ try:
+ imap.close()
+ except Exception as e:
+ _LOG.error(e)
+ imap.logout()
+
def _decode_header(header):
"""Decode RFC-2047-encoded headers to Unicode strings
raise _error.SendmailError() from e
def send(sender, recipient, message, config=None, section='DEFAULT'):
- if config.getboolean(section, 'use-smtp'):
+ protocol = config.get(section, 'email-protocol'):
+ if protocol == 'smtp':
smtp_send(sender, recipient, message)
+ elif protocol == 'imap':
+ smtp_send(message)
else:
sendmail_send(sender, recipient, message)
self.username = username
+class IMAPConnectionError (ValueError, RSS2EmailError):
+ def __init__(self, server, port, message=None):
+ if message is None:
+ message = 'could not connect to mail server {}:{}'.format(
+ server, port)
+ super(IMAPConnectionError, self).__init__(message=message)
+ self.server = server
+ self.port = port
+
+ def log(self):
+ super(IMAPConnectionError, self).log()
+ _LOG.warning(
+ 'check your config file to confirm that imap-server and other '
+ 'mail server settings are configured properly')
+ if hasattr(self.__cause__, 'reason'):
+ _LOG.error('reason: {}'.format(self.__cause__.reason))
+
+
+class IMAPAuthenticationError (IMAPConnectionError):
+ def __init__(self, server, port, username):
+ message = (
+ 'could not authenticate with mail server {}:{} as user {}'.format(
+ server, port, username))
+ super(IMAPAuthenticationError, self).__init__(
+ server=server, port=port, message=message)
+ self.username = username
+
+
class SendmailError (RSS2EmailError):
def __init__(self, status=None, stdout=None, stderr=None):
if status: