Esempio n. 1
0
    def connect_pop(self):
        #this method return pop connection
        try:
            if cint(self.settings.use_ssl):
                self.pop = Timed_POP3_SSL(
                    self.settings.host,
                    timeout=dataent.conf.get("pop_timeout"))
            else:
                self.pop = Timed_POP3(self.settings.host,
                                      timeout=dataent.conf.get("pop_timeout"))

            self.pop.user(self.settings.username)
            self.pop.pass_(self.settings.password)

            # connection established!
            return True

        except _socket.error:
            # log performs rollback and logs error in Error Log
            log("receive.connect_pop")

            # Invalid mail server -- due to refusing connection
            dataent.msgprint(
                _('Invalid Mail Server. Please rectify and try again.'))
            raise

        except poplib.error_proto as e:
            if self.is_temporary_system_problem(e):
                return False

            else:
                dataent.msgprint(
                    _('Invalid User Name or Support Password. Please rectify and try again.'
                      ))
                raise
Esempio n. 2
0
def execute_job(site, method, event, job_name, kwargs, user=None, is_async=True, retry=0):
	'''Executes job in a worker, performs commit/rollback and logs if there is any error'''
	from dataent.utils.scheduler import log

	if is_async:
		dataent.connect(site)
		if os.environ.get('CI'):
			dataent.flags.in_test = True

		if user:
			dataent.set_user(user)

	if isinstance(method, string_types):
		method_name = method
		method = dataent.get_attr(method)
	else:
		method_name = cstr(method.__name__)

	try:
		method(**kwargs)

	except (pymysql.InternalError, dataent.RetryBackgroundJobError) as e:
		dataent.db.rollback()

		if (retry < 5 and
			(isinstance(e, dataent.RetryBackgroundJobError) or e.args[0] in (ER.LOCK_DEADLOCK, ER.LOCK_WAIT_TIMEOUT))):
			# retry the job if
			# 1213 = deadlock
			# 1205 = lock wait timeout
			# or RetryBackgroundJobError is explicitly raised
			dataent.destroy()
			time.sleep(retry+1)

			return execute_job(site, method, event, job_name, kwargs,
				is_async=is_async, retry=retry+1)

		else:
			log(method_name, message=repr(locals()))
			raise

	except:
		dataent.db.rollback()
		log(method_name, message=repr(locals()))
		raise

	else:
		dataent.db.commit()

	finally:
		if is_async:
			dataent.destroy()
Esempio n. 3
0
    def retrieve_message(self, message_meta, msg_num=None):
        incoming_mail = None
        try:
            self.validate_message_limits(message_meta)

            if cint(self.settings.use_imap):
                status, message = self.imap.uid(
                    'fetch', message_meta,
                    '(BODY.PEEK[] BODY.PEEK[HEADER] FLAGS)')
                raw = message[0]

                self.get_email_seen_status(message_meta, raw[0])
                self.latest_messages.append(raw[1])
            else:
                msg = self.pop.retr(msg_num)
                self.latest_messages.append(b'\n'.join(msg[1]))
        except (TotalSizeExceededError, EmailTimeoutError):
            # propagate this error to break the loop
            self.errors = True
            raise

        except Exception as e:
            if self.has_login_limit_exceeded(e):
                self.errors = True
                raise LoginLimitExceeded(e)

            else:
                # log performs rollback and logs error in Error Log
                log("receive.get_messages",
                    self.make_error_msg(msg_num, incoming_mail))
                self.errors = True
                dataent.db.rollback()

                if not cint(self.settings.use_imap):
                    self.pop.dele(msg_num)
                else:
                    # mark as seen if email sync rule is UNSEEN (syncing only unseen mails)
                    if self.settings.email_sync_rule == "UNSEEN":
                        self.imap.uid('STORE', message_meta, '+FLAGS',
                                      '(\\SEEN)')
        else:
            if not cint(self.settings.use_imap):
                self.pop.dele(msg_num)
            else:
                # mark as seen if email sync rule is UNSEEN (syncing only unseen mails)
                if self.settings.email_sync_rule == "UNSEEN":
                    self.imap.uid('STORE', message_meta, '+FLAGS', '(\\SEEN)')
Esempio n. 4
0
def send_newsletter(newsletter):
	try:
		doc = dataent.get_doc("Newsletter", newsletter)
		doc.queue_all()

	except:
		dataent.db.rollback()

		# wasn't able to send emails :(
		doc.db_set("email_sent", 0)
		dataent.db.commit()

		log("send_newsletter")

		raise

	else:
		dataent.db.commit()
Esempio n. 5
0
def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=False):
	'''Send Email Queue with given smtpserver'''

	email = dataent.db.sql('''select
			name, status, communication, message, sender, reference_doctype,
			reference_name, unsubscribe_param, unsubscribe_method, expose_recipients,
			show_as_cc, add_unsubscribe_link, attachments, retry
		from
			`tabEmail Queue`
		where
			name=%s
		for update''', email, as_dict=True)[0]

	recipients_list = dataent.db.sql('''select name, recipient, status from
		`tabEmail Queue Recipient` where parent=%s''',email.name,as_dict=1)

	if dataent.are_emails_muted():
		dataent.msgprint(_("Emails are muted"))
		return

	if cint(dataent.defaults.get_defaults().get("hold_queue"))==1 :
		return

	if email.status not in ('Not Sent','Partially Sent') :
		# rollback to release lock and return
		dataent.db.rollback()
		return

	dataent.db.sql("""update `tabEmail Queue` set status='Sending', modified=%s where name=%s""",
		(now_datetime(), email.name), auto_commit=auto_commit)

	if email.communication:
		dataent.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit)

	try:
		if not dataent.flags.in_test:
			if not smtpserver: smtpserver = SMTPServer()
			smtpserver.setup_email_account(email.reference_doctype, sender=email.sender)

		for recipient in recipients_list:
			if recipient.status != "Not Sent":
				continue

			message = prepare_message(email, recipient.recipient, recipients_list)
			if not dataent.flags.in_test:
				smtpserver.sess.sendmail(email.sender, recipient.recipient, encode(message))

			recipient.status = "Sent"
			dataent.db.sql("""update `tabEmail Queue Recipient` set status='Sent', modified=%s where name=%s""",
				(now_datetime(), recipient.name), auto_commit=auto_commit)

		#if all are sent set status
		if any("Sent" == s.status for s in recipients_list):
			dataent.db.sql("""update `tabEmail Queue` set status='Sent', modified=%s where name=%s""",
				(now_datetime(), email.name), auto_commit=auto_commit)
		else:
			dataent.db.sql("""update `tabEmail Queue` set status='Error', error=%s
				where name=%s""", ("No recipients to send to", email.name), auto_commit=auto_commit)
		if dataent.flags.in_test:
			dataent.flags.sent_mail = message
			return
		if email.communication:
			dataent.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit)

	except (smtplib.SMTPServerDisconnected,
			smtplib.SMTPConnectError,
			smtplib.SMTPHeloError,
			smtplib.SMTPAuthenticationError,
			JobTimeoutException):

		# bad connection/timeout, retry later

		if any("Sent" == s.status for s in recipients_list):
			dataent.db.sql("""update `tabEmail Queue` set status='Partially Sent', modified=%s where name=%s""",
				(now_datetime(), email.name), auto_commit=auto_commit)
		else:
			dataent.db.sql("""update `tabEmail Queue` set status='Not Sent', modified=%s where name=%s""",
				(now_datetime(), email.name), auto_commit=auto_commit)

		if email.communication:
			dataent.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit)

		# no need to attempt further
		return

	except Exception as e:
		dataent.db.rollback()

		if email.retry < 3:
			dataent.db.sql("""update `tabEmail Queue` set status='Not Sent', modified=%s, retry=retry+1 where name=%s""",
				(now_datetime(), email.name), auto_commit=auto_commit)
		else:
			if any("Sent" == s.status for s in recipients_list):
				dataent.db.sql("""update `tabEmail Queue` set status='Partially Errored', error=%s where name=%s""",
					(text_type(e), email.name), auto_commit=auto_commit)
			else:
				dataent.db.sql("""update `tabEmail Queue` set status='Error', error=%s
					where name=%s""", (text_type(e), email.name), auto_commit=auto_commit)

		if email.communication:
			dataent.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit)

		if now:
			print(dataent.get_traceback())
			raise e

		else:
			# log to Error Log
			log('dataent.email.queue.flush', text_type(e))
Esempio n. 6
0
	def receive(self, test_mails=None):
		"""Called by scheduler to receive emails from this EMail account using POP3/IMAP."""
		def get_seen(status):
			if not status:
				return None
			seen = 1 if status == "SEEN" else 0
			return seen

		if self.enable_incoming:
			uid_list = []
			exceptions = []
			seen_status = []
			uid_reindexed = False

			if dataent.local.flags.in_test:
				incoming_mails = test_mails
			else:
				email_sync_rule = self.build_email_sync_rule()

				email_server = None
				try:
					email_server = self.get_incoming_server(in_receive=True, email_sync_rule=email_sync_rule)
				except Exception:
					dataent.log_error(title=_("Error while connecting to email account {0}").format(self.name))

				if not email_server:
					return

				emails = email_server.get_messages()
				if not emails:
					return

				incoming_mails = emails.get("latest_messages", [])
				uid_list = emails.get("uid_list", [])
				seen_status = emails.get("seen_status", [])
				uid_reindexed = emails.get("uid_reindexed", False)

			for idx, msg in enumerate(incoming_mails):
				uid = None if not uid_list else uid_list[idx]
				try:
					args = {
						"uid": uid,
						"seen": None if not seen_status else get_seen(seen_status.get(uid, None)),
						"uid_reindexed": uid_reindexed
					}
					communication = self.insert_communication(msg, args=args)

				except SentEmailInInbox:
					dataent.db.rollback()

				except Exception:
					dataent.db.rollback()
					log('email_account.receive')
					if self.use_imap:
						self.handle_bad_emails(email_server, uid, msg, dataent.get_traceback())
					exceptions.append(dataent.get_traceback())

				else:
					dataent.db.commit()
					if communication:
						attachments = [d.file_name for d in communication._attachments]
						communication.notify(attachments=attachments, fetched_from_email_account=True)

			#notify if user is linked to account
			if len(incoming_mails)>0 and not dataent.local.flags.in_test:
				dataent.publish_realtime('new_email', {"account":self.email_account_name, "number":len(incoming_mails)})

			if exceptions:
				raise Exception(dataent.as_json(exceptions))
Esempio n. 7
0
def sendmail(communication_name,
             print_html=None,
             print_format=None,
             attachments=None,
             recipients=None,
             cc=None,
             bcc=None,
             lang=None,
             session=None,
             print_letterhead=None):
    try:

        if lang:
            dataent.local.lang = lang

        if session:
            # hack to enable access to private files in PDF
            session['data'] = dataent._dict(session['data'])
            dataent.local.session.update(session)

        if print_letterhead:
            dataent.flags.print_letterhead = print_letterhead

        # upto 3 retries
        for i in range(3):
            try:
                communication = dataent.get_doc("Communication",
                                                communication_name)
                communication._notify(print_html=print_html,
                                      print_format=print_format,
                                      attachments=attachments,
                                      recipients=recipients,
                                      cc=cc,
                                      bcc=bcc)

            except pymysql.InternalError as e:
                # deadlock, try again
                if e.args[0] == ER.LOCK_DEADLOCK:
                    dataent.db.rollback()
                    time.sleep(1)
                    continue
                else:
                    raise
            else:
                break

    except:
        traceback = log(
            "dataent.core.doctype.communication.email.sendmail",
            dataent.as_json({
                "communication_name": communication_name,
                "print_html": print_html,
                "print_format": print_format,
                "attachments": attachments,
                "recipients": recipients,
                "cc": cc,
                "bcc": bcc,
                "lang": lang
            }))
        dataent.logger(__name__).error(traceback)
        raise