summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Totzke <patricktotzke@gmail.com>2011-12-25 07:48:33 -0800
committerPatrick Totzke <patricktotzke@gmail.com>2011-12-25 07:48:33 -0800
commitfd86c055736f23bb117a3888cca25fb4f3ee67e3 (patch)
treee597ccb3cc6f897945fc1ab59cdcc21f8b7e8eda
parentfab8f8a5b19302d289a81a1e8040bee8760d87f2 (diff)
parenta73d92ce57c5bc96d35e7cb7ba3fc432bca1fdd4 (diff)
Merge pull request #201 from teythoon/feature-add-sent-mails-to-notmuch
Feature add sent mails to notmuch
-rw-r--r--CUSTOMIZE.md3
-rw-r--r--alot/account.py60
-rw-r--r--alot/commands/envelope.py8
-rw-r--r--alot/db.py17
-rwxr-xr-xalot/init.py6
5 files changed, 72 insertions, 22 deletions
diff --git a/CUSTOMIZE.md b/CUSTOMIZE.md
index 14e646b0..febcf14f 100644
--- a/CUSTOMIZE.md
+++ b/CUSTOMIZE.md
@@ -60,6 +60,9 @@ Here's a full list of the interpreted keywords in account sections:
# where to store outgoing mail
sent_box = maildir:///home/you/mail//Sent
+ # how to tag sent mails [default: sent]. seperate multiple tags with ','.
+ sent_tags = sent
+
# file to append before sending
signature = ~/your_vcard_for_this_account.vcs
# signature file's name as it appears in outgoing mails
diff --git a/alot/account.py b/alot/account.py
index 6eb9f099..71398c22 100644
--- a/alot/account.py
+++ b/alot/account.py
@@ -4,12 +4,14 @@ import time
import re
import email
import os
+import glob
import shlex
from ConfigParser import SafeConfigParser
from urlparse import urlparse
import helper
+class SendingMailFailed(RuntimeError): pass
class Account(object):
"""
@@ -38,10 +40,11 @@ class Account(object):
abook = None
"""addressbook (:class:`AddressBook`) managing this accounts contacts"""
- def __init__(self, address=None, aliases=None, realname=None, gpg_key=None,
- signature=None, signature_filename=None, sent_box=None,
- draft_box=None, abook=None):
-
+ def __init__(self, dbman, address=None, aliases=None, realname=None,
+ gpg_key=None, signature=None, signature_filename=None,
+ sent_box=None, sent_tags=['sent'], draft_box=None,
+ draft_tags=['draft'], abook=None):
+ self.dbman = dbman
self.address = address
self.abook = abook
self.aliases = []
@@ -65,6 +68,7 @@ class Account(object):
self.sent_box = mailbox.Babyl(mburl.path)
elif mburl.scheme == 'mmdf':
self.sent_box = mailbox.MMDF(mburl.path)
+ self.sent_tags = sent_tags
self.draft_box = None
if draft_box:
@@ -79,8 +83,9 @@ class Account(object):
self.draft_box = mailbox.Babyl(mburl.path)
elif mburl.scheme == 'mmdf':
self.draft_box = mailbox.MMDF(mburl.path)
+ self.draft_tags = draft_tags
- def store_mail(self, mbx, mail):
+ def store_mail(self, mbx, mail, tags = None):
"""
stores given mail in mailbox. If mailbox is maildir, set the S-flag.
@@ -88,6 +93,8 @@ class Account(object):
:type mbx: :class:`mailbox.Mailbox`
:param mail: the mail to store
:type mail: :class:`email.message.Message` or str
+ :param tags: if given, add the mail to the notmuch index and tag it
+ :type tags: list of str
"""
mbx.lock()
if isinstance(mbx, mailbox.Maildir):
@@ -95,17 +102,26 @@ class Account(object):
msg.set_flags('S')
else:
msg = mailbox.Message(mail)
- mbx.add(mail)
+ message_id = mbx.add(mail)
mbx.flush()
mbx.unlock()
+ if isinstance(mbx, mailbox.Maildir) and tags != None:
+ # this is a dirty hack to get the path to the newly added file
+ # I wish the mailbox module were more helpful...
+ path = glob.glob(os.path.join(mbx._path, '*', message_id + '*'))[0]
+
+ message = self.dbman.add_message(path)
+ message.add_tags(tags)
+ self.dbman.flush()
+
def store_sent_mail(self, mail):
"""
stores mail (:class:`email.message.Message` or str) in send-store if
:attr:`sent_box` is set.
"""
if self.sent_box is not None:
- self.store_mail(self.sent_box, mail)
+ self.store_mail(self.sent_box, mail, self.sent_tags)
def store_draft_mail(self, mail):
"""
@@ -113,7 +129,7 @@ class Account(object):
:attr:`draft_box` is set.
"""
if self.draft_box is not None:
- self.store_mail(self.sent_box, mail)
+ self.store_mail(self.sent_box, mail, self.draft_tags)
def send_mail(self, mail):
"""
@@ -121,8 +137,7 @@ class Account(object):
:param mail: the mail to send
:type mail: :class:`email.message.Message` or string
- :returns: None if successful and a string with the reason
- for failure otherwise.
+ :raises: :class:`alot.account.SendingMailFailed` if an error occured
"""
return 'not implemented'
@@ -130,12 +145,14 @@ class Account(object):
class SendmailAccount(Account):
""":class:`Account` that pipes a message to a `sendmail` shell command for
sending"""
- def __init__(self, cmd, **kwargs):
+ def __init__(self, dbman, cmd, **kwargs):
"""
+ :param dbman: the database manager instance
+ :type dbman: :class:`~alot.db.DBManager`
:param cmd: sendmail command to use for this account
:type cmd: str
"""
- Account.__init__(self, **kwargs)
+ super(SendmailAccount, self).__init__(dbman, **kwargs)
self.cmd = cmd
def send_mail(self, mail):
@@ -143,9 +160,8 @@ class SendmailAccount(Account):
cmdlist = shlex.split(self.cmd.encode('utf-8', errors='ignore'))
out, err, retval = helper.call_cmd(cmdlist, stdin=mail.as_string())
if err:
- return err + '. sendmail_cmd set to: %s' % self.cmd
+ raise SendingMailFailed('%s. sendmail_cmd set to: %s' % (err, self.cmd))
self.store_sent_mail(mail)
- return None
class AccountManager(object):
@@ -165,14 +181,19 @@ class AccountManager(object):
'abook_command',
'abook_regexp',
'sent_box',
- 'draft_box']
+ 'sent_tags',
+ 'draft_box',
+ 'draft_tags']
manditory = ['realname', 'address']
+ parse_lists = ['sent_tags', 'draft_tags']
accountmap = {}
accounts = []
ordered_addresses = []
- def __init__(self, config):
+ def __init__(self, dbman, config):
"""
+ :param dbman: the database manager instance
+ :type dbman: :class:`~alot.db.DBManager`
:param config: the config object to read account information from
:type config: :class:`~alot.settings.AlotConfigParser`.
"""
@@ -195,14 +216,17 @@ class AccountManager(object):
to_set = self.manditory
for o in options:
- args[o] = config.get(s, o)
+ if o not in self.parse_lists:
+ args[o] = config.get(s, o)
+ else:
+ args[o] = config.getstringlist(s, o)
if o in to_set:
to_set.remove(o) # removes obligation
if not to_set: # all manditory fields were present
sender_type = args.pop('type', 'sendmail')
if sender_type == 'sendmail':
cmd = args.pop('sendmail_command', 'sendmail')
- newacc = (SendmailAccount(cmd, **args))
+ newacc = (SendmailAccount(dbman, cmd, **args))
self.accountmap[newacc.address] = newacc
self.accounts.append(newacc)
for alias in newacc.aliases:
diff --git a/alot/commands/envelope.py b/alot/commands/envelope.py
index 21b6aa26..5e54b63f 100644
--- a/alot/commands/envelope.py
+++ b/alot/commands/envelope.py
@@ -8,6 +8,7 @@ from twisted.internet.defer import inlineCallbacks
import threading
import datetime
+from alot.account import SendingMailFailed
from alot import buffers
from alot import commands
from alot.commands import Command, registerCommand
@@ -129,7 +130,12 @@ class SendCommand(Command):
def thread_code():
mail = envelope.construct_mail()
- os.write(write_fd, account.send_mail(mail) or 'success')
+ try:
+ account.send_mail(mail)
+ except SendingMailFailed as e:
+ os.write(write_fd, unicode(e))
+ else:
+ os.write(write_fd, 'success')
thread = threading.Thread(target=thread_code)
thread.start()
diff --git a/alot/db.py b/alot/db.py
index 5a562541..7dce0471 100644
--- a/alot/db.py
+++ b/alot/db.py
@@ -249,6 +249,23 @@ class DBManager(object):
db = Database(path=self.path, mode=mode)
return db.create_query(querystring)
+ def add_message(self, path):
+ """
+ Adds a file to the notmuch index.
+
+ :param path: path to the file
+ :type path: str
+ :returns: the message object corresponding the added message
+ :rtype: :class:`alot.message.Message`
+ """
+ db = Database(path=self.path, mode=Database.MODE.READ_WRITE)
+ try:
+ message, status = db.add_message(path,
+ sync_maildir_flags=True)
+ except NotmuchError as e:
+ raise DatabaseError(unicode(e))
+
+ return Message(self, message)
class Thread(object):
"""
diff --git a/alot/init.py b/alot/init.py
index 064eaf2e..8f5665e3 100755
--- a/alot/init.py
+++ b/alot/init.py
@@ -128,12 +128,12 @@ def main():
logger = logging.getLogger()
#logger.debug(commands.COMMANDS)
- #accountman
- aman = AccountManager(settings.config)
-
# get ourselves a database manager
dbman = DBManager(path=args['mailindex-path'], ro=args['read-only'])
+ #accountman
+ aman = AccountManager(dbman, settings.config)
+
# get initial searchstring
try:
if args.subCommand == 'search':