Example #1
0
def test_remote_save_draft(db, config, message):
    """ Tests the save_draft function, which saves the draft to the remote. """
    from inbox.actions.backends.gmail import remote_save_draft
    from inbox.sendmail.base import _parse_recipients
    from inbox.sendmail.message import create_email, Recipients
    from inbox.models import Account

    account = db.session.query(Account).get(ACCOUNT_ID)
    to, subject, body = message
    to_addr = _parse_recipients(to)
    recipients = Recipients(to_addr, [], [])
    email = create_email(account.sender_name, account.email_address, None,
                         recipients, subject, body, None)
    date = datetime.utcnow()

    remote_save_draft(account, account.drafts_folder.name, email.to_string(),
                      db.session, date)

    with crispin_client(account.id, account.provider) as c:
        criteria = ['NOT DELETED', 'SUBJECT "{0}"'.format(subject)]

        c.conn.select_folder(account.drafts_folder.name, readonly=False)

        draft_uids = c.conn.search(criteria)
        assert draft_uids, 'Message missing from Drafts folder'

        flags = c.conn.get_flags(draft_uids)
        for uid in draft_uids:
            f = flags.get(uid)
            assert f and '\\Draft' in f, "Message missing '\\Draft' flag"

        c.conn.delete_messages(draft_uids)
        c.conn.expunge()
Example #2
0
def save_draft(account_id, message_id, db_session):
    """ Sync a new/updated draft back to the remote backend. """
    account = db_session.query(Account).get(account_id)
    message = db_session.query(Message).get(message_id)
    if message is None:
        log.info('tried to save nonexistent message as draft',
                 message_id=message_id,
                 account_id=account_id)
        return
    if not message.is_draft:
        log.warning('tried to save non-draft message as draft',
                    message_id=message_id,
                    account_id=account_id)
        return

    recipients = Recipients(message.to_addr, message.cc_addr, message.bcc_addr)
    blocks = [p.block for p in message.attachments]
    attachments = generate_attachments(blocks)
    mimemsg = create_email(account.sender_name, account.email_address,
                           message.inbox_uid, recipients, message.subject,
                           message.sanitized_body, attachments)

    if account.drafts_folder is None:
        # account has no detected drafts folder - create one.
        drafts_folder = Folder.find_or_create(db_session, account, 'Drafts',
                                              'drafts')
        account.drafts_folder = drafts_folder

    remote_save_draft = module_registry[account.provider].remote_save_draft
    remote_save_draft(account, account.drafts_folder.name, mimemsg.to_string(),
                      message.created_at)
Example #3
0
def _send(account_id, draft_id, db_session):
    """Send the draft with id = `draft_id`."""
    account = db_session.query(Account).get(account_id)

    try:
        sendmail_client = get_sendmail_client(account)
    except SendMailException:
        log.error('Send Error', message="Failed to create sendmail client.",
                  account_id=account_id)
        raise
    try:
        draft = db_session.query(Message).filter(
            Message.id == draft_id).one()

    except NoResultFound:
        log.info('Send Error',
                 message='NoResultFound for draft_id {0}'.format(draft_id),
                 account_id=account_id)
        raise SendMailException('No draft with id {0}'.format(draft_id))

    except MultipleResultsFound:
        log.info('Send Error',
                 message='MultipleResultsFound for draft_id'
                         '{0}'.format(draft_id),
                 account_id=account_id)
        raise SendMailException('Multiple drafts with id {0}'.format(
            draft_id))

    if not draft.is_draft or draft.is_sent:
        return

    recipients = Recipients(draft.to_addr, draft.cc_addr, draft.bcc_addr)

    if not draft.is_reply:
        sendmail_client.send_new(db_session, draft, recipients)
    else:
        sendmail_client.send_reply(db_session, draft, recipients)

    if account.provider == 'icloud':
        # Special case because iCloud doesn't save
        # sent messages.
        schedule_action('save_sent_email', draft, draft.namespace.id,
                        db_session)

    # Update message
    draft.is_sent = True
    draft.is_draft = False
    draft.state = 'sent'

    # Update thread
    sent_tag = account.namespace.tags['sent']
    draft_tag = account.namespace.tags['drafts']
    draft.thread.apply_tag(sent_tag)
    # Remove the drafts tag from the thread if there are no more drafts.
    if not draft.thread.drafts:
        draft.thread.remove_tag(draft_tag)

    return draft
Example #4
0
def _create_email(account, message, generate_new_uid=False):
    recipients = Recipients(message.to_addr, message.cc_addr,
                            message.bcc_addr)
    blocks = [p.block for p in message.attachments]
    attachments = generate_attachments(blocks)

    inbox_uid = message.inbox_uid
    if generate_new_uid:
        inbox_uid = None

    return create_email(account.name, account.email_address,
                        inbox_uid, recipients, message.subject,
                        message.sanitized_body, attachments)
Example #5
0
def save_draft(account_id, message_id, db_session):
    """ Sync a new/updated draft back to the remote backend. """
    account = db_session.query(Account).get(account_id)
    message = db_session.query(Message).get(message_id)
    assert message.is_draft

    recipients = Recipients(message.to_addr, message.cc_addr, message.bcc_addr)
    attachments = generate_attachments(message.attachments)
    mimemsg = create_email(account.sender_name, account.email_address,
                           message.inbox_uid, recipients, message.subject,
                           message.sanitized_body, attachments)

    remote_save_draft = module_registry[account.provider].remote_save_draft
    remote_save_draft(account, account.drafts_folder.name, mimemsg.to_string(),
                      message.created_at)
Example #6
0
def test_remote_delete_draft(db, config, message):
    """
    Tests the delete_draft function, which deletes the draft from the
    remote.

    """
    from inbox.actions.backends.gmail import remote_delete_draft, remote_save_draft
    from inbox.models import Account
    from inbox.sendmail.base import _parse_recipients
    from inbox.sendmail.message import Recipients, create_email

    account = db.session.query(Account).get(ACCOUNT_ID)
    to, subject, body = message
    to_addr = _parse_recipients(to)
    recipients = Recipients(to_addr, [], [])
    email = create_email(
        account.sender_name,
        account.email_address,
        None,
        recipients,
        subject,
        body,
        None,
    )
    date = datetime.utcnow()

    # Save on remote
    remote_save_draft(account, account.drafts_folder.name, email.to_string(),
                      db.session, date)

    inbox_uid = email.headers["X-INBOX-ID"]

    with crispin_client(account.id, account.provider) as c:
        criteria = [
            "DRAFT", "NOT DELETED", "HEADER X-INBOX-ID {0}".format(inbox_uid)
        ]

        c.conn.select_folder(account.drafts_folder.name, readonly=False)
        uids = c.conn.search(criteria)
        assert uids, "Message missing from Drafts folder"

        # Delete on remote
        remote_delete_draft(account, account.drafts_folder.name, inbox_uid,
                            db.session)

        c.conn.select_folder(account.drafts_folder.name, readonly=False)
        uids = c.conn.search(criteria)
        assert not uids, "Message still in Drafts folder"
Example #7
0
def _send(account_id, draft_id, db_session):
    """Send the draft with id = `draft_id`."""
    account = db_session.query(Account).get(account_id)

    log = get_logger()
    sendmail_client = get_sendmail_client(account)
    try:
        draft = db_session.query(Message).filter(Message.id == draft_id).one()

    except NoResultFound:
        log.info('NoResultFound for draft_id {0}'.format(draft_id))
        raise SendMailException('No draft with id {0}'.format(draft_id))

    except MultipleResultsFound:
        log.info('MultipleResultsFound for draft_id {0}'.format(draft_id))
        raise SendMailException('Multiple drafts with id {0}'.format(draft_id))

    if not draft.is_draft or draft.is_sent:
        return

    recipients = Recipients(draft.to_addr, draft.cc_addr, draft.bcc_addr)
    if not draft.is_reply:
        sendmail_client.send_new(db_session, draft, recipients)
    else:
        sendmail_client.send_reply(db_session, draft, recipients)

    # Update message
    draft.is_sent = True
    draft.is_draft = False
    draft.state = 'sent'

    # Update thread
    sent_tag = account.namespace.tags['sent']
    draft_tag = account.namespace.tags['drafts']
    draft.thread.apply_tag(sent_tag)
    # Remove the drafts tag from the thread if there are no more drafts.
    if not draft.thread.drafts:
        draft.thread.remove_tag(draft_tag)

    return draft
Example #8
0
def save_draft(account_id, message_id, db_session):
    """ Sync a new/updated draft back to the remote backend. """
    account = db_session.query(Account).get(account_id)
    message = db_session.query(Message).get(message_id)
    assert message.is_draft

    recipients = Recipients(message.to_addr, message.cc_addr, message.bcc_addr)
    attachments = generate_attachments(message.attachments)
    mimemsg = create_email(account.sender_name, account.email_address,
                           message.inbox_uid, recipients, message.subject,
                           message.sanitized_body, attachments)

    remote_save_draft = module_registry[account.provider].remote_save_draft
    remote_save_draft(account, account.drafts_folder.name, mimemsg.to_string(),
                      message.created_at)

    # If this draft is created by an update_draft() call,
    # delete the one it supercedes on the remote.
    # Needed because our update_draft() creates a new draft
    # message but the user expects to see the one
    # updated draft only.
    if message.parent_draft:
        return delete_draft(account_id, message.parent_draft.id, db_session)