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()
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)
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
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)
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)
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"
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
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)