Ejemplo n.º 1
0
 def get_or_create_any_coordinator(cls):
     coordinator = cls.objects.filter(
         is_active=True, is_repanier_admin=True).order_by('id').first()
     if coordinator is None:
         # Set the first staff member as coordinator if possible
         coordinator = cls.objects.all().order_by('id').first()
         if coordinator is not None:
             coordinator.is_active = True
             coordinator.is_repanier_admin = True
             coordinator.save(
                 update_fields=["is_active", "is_repanier_admin"])
     if coordinator is None:
         # Create the very first staff member
         from repanier.apps import REPANIER_SETTINGS_GROUP_NAME
         from repanier.models.customer import Customer
         very_first_customer = Customer.get_or_create_the_very_first_customer(
         )
         user_model = get_user_model()
         user = user_model.objects.create_user(username="******".format(
             uuid.uuid1(),
             settings.REPANIER_SETTINGS_ALLOWED_MAIL_EXTENSION),
                                               email=EMPTY_STRING,
                                               password=None,
                                               first_name=EMPTY_STRING,
                                               last_name=EMPTY_STRING)
         coordinator = Staff.objects.create(
             user=user,
             is_active=True,
             is_repanier_admin=True,
             is_webmaster=True,
             customer_responsible=very_first_customer)
         cur_language = translation.get_language()
         for language in settings.PARLER_LANGUAGES[settings.SITE_ID]:
             language_code = language["code"]
             translation.activate(language_code)
             coordinator.set_current_language(language_code)
             coordinator.long_name = _("Coordinator")
             coordinator.save()
         translation.activate(cur_language)
     return coordinator
Ejemplo n.º 2
0
    def get_or_create_any_coordinator(cls):
        coordinator = (
            (
                cls.objects.filter(
                    is_active=True, is_repanier_admin=True, can_be_contacted=True
                )
                .order_by("id")
                .first()
            )
            or (
                cls.objects.filter(is_active=True, is_repanier_admin=True)
                .order_by("id")
                .first()
            )
            or (cls.objects.filter(is_active=True).order_by("id").first())
            or (cls.objects.order_by("id").first())
        )
        if coordinator is None:
            # Create the very first staff member
            from repanier.models.customer import Customer

            very_first_customer = Customer.get_or_create_the_very_first_customer()
            coordinator = Staff.objects.create(
                is_active=True,
                is_repanier_admin=True,
                is_webmaster=True,
                customer_responsible=very_first_customer,
                can_be_contacted=True,
            )
            cur_language = translation.get_language()
            for language in settings.PARLER_LANGUAGES[settings.SITE_ID]:
                language_code = language["code"]
                translation.activate(language_code)
                coordinator.set_current_language(language_code)
                coordinator.long_name = _("Coordinator")
                coordinator.save()
            translation.activate(cur_language)
        return coordinator
Ejemplo n.º 3
0
    def init_repanier(cls):
        from repanier.const import DECIMAL_ONE, PERMANENCE_NAME_PERMANENCE, CURRENCY_EUR
        from repanier.models.producer import Producer
        from repanier.models.bankaccount import BankAccount
        from repanier.models.staff import Staff
        from repanier.models.customer import Customer

        # Create the configuration record managed via the admin UI
        config = Configuration.objects.filter(id=DECIMAL_ONE).first()
        if config is not None:
            return config
        group_name = settings.REPANIER_SETTINGS_GROUP_NAME
        site = Site.objects.get_current()
        if site is not None:
            site.name = group_name
            site.domain = group_name
            site.save()
        config = Configuration.objects.create(
            group_name=group_name,
            name=PERMANENCE_NAME_PERMANENCE,
            bank_account="BE99 9999 9999 9999",
            currency=CURRENCY_EUR)
        config.init_email()
        config.save()

        # Create firsts users
        Producer.get_or_create_group()
        customer_buyinggroup = Customer.get_or_create_group()
        very_first_customer = Customer.get_or_create_the_very_first_customer()

        BankAccount.open_account(customer_buyinggroup=customer_buyinggroup,
                                 very_first_customer=very_first_customer)

        coordinator = Staff.get_or_create_any_coordinator()
        Staff.get_or_create_order_responsible()
        Staff.get_or_create_invoice_responsible()
        # Create and publish first web page
        if not coordinator.is_webmaster:
            # This should not be the case...
            return

        from cms.models import StaticPlaceholder
        from cms.constants import X_FRAME_OPTIONS_DENY
        from cms import api
        page = api.create_page(title=_("Home"),
                               soft_root=False,
                               template=settings.CMS_TEMPLATE_HOME,
                               language=settings.LANGUAGE_CODE,
                               published=True,
                               parent=None,
                               xframe_options=X_FRAME_OPTIONS_DENY,
                               in_navigation=True)
        try:
            # New in CMS 3.5
            page.set_as_homepage()
        except:
            pass

        placeholder = page.placeholders.get(slot="home-hero")
        api.add_plugin(placeholder=placeholder,
                       plugin_type='TextPlugin',
                       language=settings.LANGUAGE_CODE,
                       body=settings.CMS_TEMPLATE_HOME_HERO)
        placeholder = page.placeholders.get(slot="home-col-1")
        api.add_plugin(placeholder=placeholder,
                       plugin_type='TextPlugin',
                       language=settings.LANGUAGE_CODE,
                       body=settings.CMS_TEMPLATE_HOME_COL_1)
        placeholder = page.placeholders.get(slot="home-col-2")
        api.add_plugin(placeholder=placeholder,
                       plugin_type='TextPlugin',
                       language=settings.LANGUAGE_CODE,
                       body=settings.CMS_TEMPLATE_HOME_COL_2)
        placeholder = page.placeholders.get(slot="home-col-3")
        api.add_plugin(placeholder=placeholder,
                       plugin_type='TextPlugin',
                       language=settings.LANGUAGE_CODE,
                       body=settings.CMS_TEMPLATE_HOME_COL_3)
        static_placeholder = StaticPlaceholder(code="footer",
                                               # site_id=1
                                               )
        static_placeholder.save()
        api.add_plugin(placeholder=static_placeholder.draft,
                       plugin_type='TextPlugin',
                       language=settings.LANGUAGE_CODE,
                       body='hello world footer')
        static_placeholder.publish(request=None,
                                   language=settings.LANGUAGE_CODE,
                                   force=True)
        api.publish_page(page=page,
                         user=coordinator.user,
                         language=settings.LANGUAGE_CODE)

        return config
Ejemplo n.º 4
0
    def init_repanier(cls):
        from repanier.const import DECIMAL_ONE, PERMANENCE_NAME_PERMANENCE, CURRENCY_EUR
        from repanier.models.producer import Producer
        from repanier.models.bankaccount import BankAccount
        from repanier.models.staff import Staff
        from repanier.models.customer import Customer
        from repanier.models.lut import LUT_DepartmentForCustomer

        logger.debug("######## start of init_repanier")

        # Create the configuration record managed via the admin UI
        config = Configuration.objects.filter(id=DECIMAL_ONE).first()
        if config is not None:
            return config
        site = Site.objects.get_current()
        if site is not None:
            site.name = settings.REPANIER_SETTINGS_GROUP_NAME
            site.domain = settings.ALLOWED_HOSTS[0]
            site.save()
        config = Configuration.objects.create(
            group_name=settings.REPANIER_SETTINGS_GROUP_NAME,
            name=PERMANENCE_NAME_PERMANENCE,
            bank_account="BE99 9999 9999 9999",
            currency=CURRENCY_EUR,
        )
        config.init_email()
        config.save()

        # Create firsts users
        Producer.get_or_create_group()
        customer_buyinggroup = Customer.get_or_create_group()
        very_first_customer = Customer.get_or_create_the_very_first_customer()

        BankAccount.open_account(
            customer_buyinggroup=customer_buyinggroup,
            very_first_customer=very_first_customer,
        )
        very_first_customer = Customer.get_or_create_the_very_first_customer()
        coordinator = Staff.get_or_create_any_coordinator()
        Staff.get_or_create_order_responsible()
        Staff.get_or_create_invoice_responsible()
        # Create and publish first web page
        if not coordinator.is_webmaster:
            # This should not be the case...
            return

        from cms.models import StaticPlaceholder
        from cms.constants import X_FRAME_OPTIONS_DENY
        from cms import api

        page = api.create_page(
            title=_("Home"),
            soft_root=False,
            template=settings.CMS_TEMPLATE_HOME,
            language=settings.LANGUAGE_CODE,
            published=True,
            parent=None,
            xframe_options=X_FRAME_OPTIONS_DENY,
            in_navigation=True,
        )
        try:
            # New in CMS 3.5
            page.set_as_homepage()
        except:
            pass

        placeholder = page.placeholders.get(slot="home-hero")
        api.add_plugin(
            placeholder=placeholder,
            plugin_type="TextPlugin",
            language=settings.LANGUAGE_CODE,
            body=settings.CMS_TEMPLATE_HOME_HERO,
        )
        static_placeholder = StaticPlaceholder(
            code="footer",
            # site_id=1
        )
        static_placeholder.save()
        api.add_plugin(
            placeholder=static_placeholder.draft,
            plugin_type="TextPlugin",
            language=settings.LANGUAGE_CODE,
            body="hello world footer",
        )
        static_placeholder.publish(
            request=None, language=settings.LANGUAGE_CODE, force=True
        )
        api.publish_page(
            page=page,
            user=coordinator.customer_responsible.user,
            language=settings.LANGUAGE_CODE,
        )

        if LUT_DepartmentForCustomer.objects.count() == 0:
            # Generate a template of LUT_DepartmentForCustomer
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Vegetable"))
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Basket of vegetables"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Salad"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Tomato"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Potato"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Green"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Cabbage"), parent=parent
            )
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Fruit"))
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Basket of fruits"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Apple"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Pear"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Plum"), parent=parent
            )
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Bakery"))
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Flour"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Bread"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Pastry"), parent=parent
            )
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Butchery"))
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Delicatessen"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Chicken"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Pork"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Beef"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Beef and pork"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Veal"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Lamb"), parent=parent
            )
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Grocery"))
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Takeaway"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Pasta"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Chocolate"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(short_name=_("Oil"), parent=parent)
            LUT_DepartmentForCustomer.objects.create(short_name=_("Egg"), parent=parent)
            LUT_DepartmentForCustomer.objects.create(short_name=_("Jam"), parent=parent)
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Cookie"), parent=parent
            )
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Creamery"))
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Dairy"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Cow cheese"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Goat cheese"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Sheep cheese"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Mixed cheese"), parent=parent
            )
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Icecream"))
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Cup of icecream"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Icecream per liter"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Icecream in frisco"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Icecream cake"), parent=parent
            )
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Sorbet"))
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Cup of sorbet"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Sorbet per liter"), parent=parent
            )
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Drink"))
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Juice"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Coffee"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(short_name=_("Tea"), parent=parent)
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Herbal tea"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Wine"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Aperitif"), parent=parent
            )
            LUT_DepartmentForCustomer.objects.create(
                short_name=_("Liqueurs"), parent=parent
            )
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Hygiene"))
            parent = LUT_DepartmentForCustomer.objects.create(short_name=_("Deposit"))
            parent = LUT_DepartmentForCustomer.objects.create(
                short_name=_("Subscription")
            )

        logger.debug("######## end of init_repanier")

        return config
Ejemplo n.º 5
0
    def _send_email_with_unsubscribe(self, email_to=None):
        from repanier.models.customer import Customer

        self.to = [email_to]
        self.cc = []
        self.bcc = []
        self.reply_to = [settings.REPANIER_SETTINGS_REPLY_ALL_EMAIL_TO]

        customer = Customer.get_customer_from_valid_email(email_to)
        if customer is not None:
            if not self.send_even_if_unsubscribed:
                if not customer.subscribe_to_email:
                    return False
                elif customer.user.last_login is not None:
                    max_2_years_in_the_past = timezone.now() - datetime.timedelta(days=426)
                    if customer.user.last_login < max_2_years_in_the_past:
                        # Do not spam someone who has never logged in since more than 1 year and 2 months
                        return False

        self.alternatives = []
        if customer is not None and self.show_customer_may_unsubscribe:
            self.attach_alternative(
                "{}{}".format(self.html_body, customer.get_html_unsubscribe_mail_footer()),
                "text/html"
            )
            self.extra_headers['List-Unsubscribe'] = customer.get_html_list_unsubscribe()
        else:
            self.attach_alternative(
                self.html_body,
                "text/html"
            )
        email_send = False
        # Email subject *must not* contain newlines
        self.subject = ''.join(self.subject.splitlines())

        logger.debug("################################## send_email")
        attempt_counter = 1
        while not email_send and attempt_counter < 3:
            attempt_counter += 1
            try:
                if settings.DEBUG:
                    # self.send()
                    logger.debug("send email to : {}".format(email_to))
                else:
                    if settings.REPANIER_SETTINGS_BCC_ALL_EMAIL_TO:
                        self.bcc = [settings.REPANIER_SETTINGS_BCC_ALL_EMAIL_TO]
                    self.send()
                email_send = True
            except SMTPRecipientsRefused as error_str:
                logger.error("################################## send_email SMTPRecipientsRefused")
                logger.error(error_str)
            except Exception as error_str:
                logger.error("################################## send_email error")
                logger.error(error_str)
                self._send_error("send_email error", error_str)
            if customer is not None:
                # customer.valid_email = valid_email
                # customer.save(update_fields=['valid_email'])
                # use vvvv because ^^^^^ will call "pre_save" function which reset valid_email to None
                Customer.objects.filter(id=customer.id).order_by('?').update(valid_email=email_send)
            time.sleep(min(1, 1 + random()))

        return email_send
Ejemplo n.º 6
0
    def _send_email_with_unsubscribe(self, email_to=None):
        from repanier.models.customer import Customer

        self.to = [email_to]
        self.cc = []
        self.bcc = []
        self.reply_to = [settings.REPANIER_SETTINGS_REPLY_ALL_EMAIL_TO]

        customer = Customer.get_customer_from_valid_email(email_to)
        if customer is not None:
            if not self.send_even_if_unsubscribed:
                if not customer.subscribe_to_email:
                    return False
                elif customer.user.last_login is not None:
                    max_2_years_in_the_past = timezone.now(
                    ) - datetime.timedelta(days=426)
                    if customer.user.last_login < max_2_years_in_the_past:
                        # Do not spam someone who has never logged in since more than 1 year and 2 months
                        return False

        self.alternatives = []
        if customer is not None and self.show_customer_may_unsubscribe:
            self.attach_alternative(
                "{}{}".format(self.html_body,
                              customer.get_html_unsubscribe_mail_footer()),
                "text/html",
            )
            self.extra_headers[
                "List-Unsubscribe"] = customer.get_html_list_unsubscribe()
        else:
            self.attach_alternative(self.html_body, "text/html")
        email_send = False
        # Email subject *must not* contain newlines
        self.subject = "".join(self.subject.splitlines())

        logger.debug("################################## send_email")
        attempt_counter = 1
        while not email_send and attempt_counter < 3:
            attempt_counter += 1
            try:
                if settings.DEBUG:
                    if settings.REPANIER_SETTINGS_BCC_ALL_EMAIL_TO:
                        self.to = [settings.REPANIER_SETTINGS_BCC_ALL_EMAIL_TO]
                        self.send()
                    else:
                        logger.debug("send email to : {}".format(email_to))
                else:
                    if settings.REPANIER_SETTINGS_BCC_ALL_EMAIL_TO:
                        self.bcc = [
                            settings.REPANIER_SETTINGS_BCC_ALL_EMAIL_TO
                        ]
                    self.send()
                email_send = True
            except SMTPRecipientsRefused as error_str:
                logger.error(
                    "################################## send_email SMTPRecipientsRefused"
                )
                logger.error(error_str)
                # reset connection : EmailMessage.get_connection() will get/open a new connection
                # before next self.send()
                self.connection = None
            except Exception as error_str:
                logger.error(
                    "################################## send_email error")
                logger.error(error_str)
                self._send_error("send_email error", error_str)
                # reset connection : EmailMessage.get_connection() will get/open a new connection
                # before next self.send()
                self.connection = None
            if customer is not None:
                # customer.valid_email = valid_email
                # customer.save(update_fields=['valid_email'])
                # use vvvv because ^^^^^ will call "pre_save" function which reset valid_email to None
                Customer.objects.filter(id=customer.id).order_by("?").update(
                    valid_email=email_send)
            time.sleep(min(1, 1 + random()))

        return email_send
Ejemplo n.º 7
0
    def init_repanier(cls):
        from repanier.const import DECIMAL_ONE, PERMANENCE_NAME_PERMANENCE, CURRENCY_EUR
        from repanier.models.producer import Producer
        from repanier.models.bankaccount import BankAccount
        from repanier.models.staff import Staff
        from repanier.models.customer import Customer

        # Create the configuration record managed via the admin UI
        config = Configuration.objects.filter(id=DECIMAL_ONE).first()
        if config is not None:
            return config
        site = Site.objects.get_current()
        if site is not None:
            site.name = settings.REPANIER_SETTINGS_GROUP_NAME
            site.domain = settings.ALLOWED_HOSTS[0]
            site.save()
        config = Configuration.objects.create(
            group_name=settings.REPANIER_SETTINGS_GROUP_NAME,
            name=PERMANENCE_NAME_PERMANENCE,
            bank_account="BE99 9999 9999 9999",
            currency=CURRENCY_EUR
        )
        config.init_email()
        config.save()

        # Create firsts users
        Producer.get_or_create_group()
        customer_buyinggroup = Customer.get_or_create_group()
        very_first_customer = Customer.get_or_create_the_very_first_customer()

        BankAccount.open_account(
            customer_buyinggroup=customer_buyinggroup,
            very_first_customer=very_first_customer
        )

        coordinator = Staff.get_or_create_any_coordinator()
        Staff.get_or_create_order_responsible()
        Staff.get_or_create_invoice_responsible()
        # Create and publish first web page
        if not coordinator.is_webmaster:
            # This should not be the case...
            return

        from cms.models import StaticPlaceholder
        from cms.constants import X_FRAME_OPTIONS_DENY
        from cms import api
        page = api.create_page(
            title=_("Home"),
            soft_root=False,
            template=settings.CMS_TEMPLATE_HOME,
            language=settings.LANGUAGE_CODE,
            published=True,
            parent=None,
            xframe_options=X_FRAME_OPTIONS_DENY,
            in_navigation=True
        )
        try:
            # New in CMS 3.5
            page.set_as_homepage()
        except:
            pass

        placeholder = page.placeholders.get(slot="home-hero")
        api.add_plugin(
            placeholder=placeholder,
            plugin_type='TextPlugin',
            language=settings.LANGUAGE_CODE,
            body=settings.CMS_TEMPLATE_HOME_HERO)
        placeholder = page.placeholders.get(slot="home-col-1")
        api.add_plugin(
            placeholder=placeholder,
            plugin_type='TextPlugin',
            language=settings.LANGUAGE_CODE,
            body=settings.CMS_TEMPLATE_HOME_COL_1)
        placeholder = page.placeholders.get(slot="home-col-2")
        api.add_plugin(
            placeholder=placeholder,
            plugin_type='TextPlugin',
            language=settings.LANGUAGE_CODE,
            body=settings.CMS_TEMPLATE_HOME_COL_2)
        placeholder = page.placeholders.get(slot="home-col-3")
        api.add_plugin(
            placeholder=placeholder,
            plugin_type='TextPlugin',
            language=settings.LANGUAGE_CODE,
            body=settings.CMS_TEMPLATE_HOME_COL_3)
        static_placeholder = StaticPlaceholder(
            code="footer",
            # site_id=1
        )
        static_placeholder.save()
        api.add_plugin(
            placeholder=static_placeholder.draft,
            plugin_type='TextPlugin',
            language=settings.LANGUAGE_CODE,
            body='hello world footer'
        )
        static_placeholder.publish(
            request=None,
            language=settings.LANGUAGE_CODE,
            force=True
        )
        api.publish_page(
            page=page,
            user=coordinator.user,
            language=settings.LANGUAGE_CODE)

        return config
Ejemplo n.º 8
0
    def _send_email_with_error_log(self):
        email_to = self.to[0]
        if not self.test_connection:
            from repanier.models.customer import Customer

            customer = Customer.get_customer_from_valid_email(email_to)
            if customer is not None:
                if not self.send_even_if_unsubscribed and not customer.subscribe_to_email:
                    return False
                elif customer.user.last_login is not None:
                    max_2_years_in_the_past = timezone.now() - datetime.timedelta(days=426)
                    if customer.user.last_login < max_2_years_in_the_past:
                        # Do not spam someone who has never logged in since more than 1 year and 2 months
                        return False
        else:
            customer = None

        self.alternatives = []
        if customer is not None and self.show_customer_may_unsubscribe:
            self.attach_alternative(
                "{}{}".format(self.html_body, customer.get_html_unsubscribe_mail_footer()),
                "text/html"
            )
            self.extra_headers['List-Unsubscribe'] = customer.get_html_list_unsubscribe()
        else:
            self.attach_alternative(
                self.html_body,
                "text/html"
            )
        email_send = False
        try_to_send = True
        # Email subject *must not* contain newlines
        self.subject = ''.join(self.subject.splitlines())
        if settings.REPANIER_SETTINGS_BCC_ALL_EMAIL_TO:
            self.bcc = [settings.REPANIER_SETTINGS_BCC_ALL_EMAIL_TO, ]

        logger.info("################################## send_email")
        attempt_counter = 1
        while not email_send and try_to_send:
            attempt_counter += 1
            try_to_send = False
            try:
                with mail.get_connection(
                        host=self.host,
                        port=self.port,
                        username=self.host_user,
                        password=self.host_password,
                        use_tls=self.use_tls,
                        use_ssl=not self.use_tls) as connection:
                    self.connection = connection
                    try:
                        if not settings.DEBUG:
                            # Do not send mail in debug mode
                            self.send()
                        else:
                            self.to = ['*****@*****.**']
                            self.send()
                        email_send = True
                    except SMTPRecipientsRefused as error_str:
                        logger.error("################################## send_email SMTPRecipientsRefused")
                        logger.error(error_str)
                        self._send_error("ERROR", error_str)
                    except Exception as error_str:
                        logger.error("################################## send_email error")
                        logger.error(error_str)
                        self._send_error("ERROR", error_str)
                    logger.info("##################################")
                    if email_send and customer is not None:
                        from repanier.models.customer import Customer

                        # customer.valid_email = valid_email
                        # customer.save(update_fields=['valid_email'])
                        # use vvvv because ^^^^^ will call "pre_save" function which reset valid_email to None
                        Customer.objects.filter(id=customer.id).order_by('?').update(valid_email=email_send)
            except SMTPAuthenticationError as error_str:
                logger.fatal("################################## send_email SMTPAuthenticationError")
                # https://support.google.com/accounts/answer/185833
                # https://support.google.com/accounts/answer/6010255
                # https://security.google.com/settings/security/apppasswords
                logger.fatal(error_str)
                self._send_error("FATAL", error_str)
            except Exception as error_str:
                if attempt_counter <= 5:
                    logger.info("################################## send_email error, retry")
                    logger.info(error_str)
                    # retry max 5 more times
                    attempt_counter += 1
                    try_to_send = True
                    time.sleep(min(5 * attempt_counter, randint(10, 20)))
                else:
                    logger.fatal("################################## send_email error, abort")
                    logger.fatal(error_str)
                    self._send_error("FATAL", error_str)

        return email_send