Как программно вызвать электронную почту для сброса пароля в django 1.7.6?

Я столкнулся с проблемой, когда мне пришлось загрузить более 200 новых пользователей в мое приложение django и сразу же отправить им электронное письмо для сброса пароля. Это должно было произойти только один раз, сделано только мной и тихо работало на бэкенде. Серфинг в Интернете привел меня только к одному более или менее правильному ответу: Trigger password сбросить электронную почту в django без браузера?. Единственная проблема заключалась в том, что этому посту было около 4 лет, и, конечно, когда я попробовал решение, оно не сработало...


person chabislav    schedule 06.05.2015    source источник


Ответы (2)


Два наиболее ценных пункта из ссылки, которую я упомянул:

  1. В самой последней версии Django нам нужно вызвать form.is_valid()
  2. Отправка электронной почты осуществляется после save().

Вот как я опросил нужных мне пользователей и отправил каждому из них ссылку для сброса пароля:

def find_users_and_send_email():
    from django.http import HttpRequest
    from django.contrib.auth.forms import PasswordResetForm
    from django.contrib.auth.models import User
    import logging
    logger = logging.getLogger(__name__)
    
    users = User.objects.filter(date_joined__gt = '2015-04-16')
    for user in users:
        try:
            if user.email:
                logger.info("Sending email for to this email:", user.email)
                form = PasswordResetForm({'email': user.email})
                
                assert form.is_valid()
                request = HttpRequest()
                request.META['SERVER_NAME'] = 'help.mydomain.com'
                request.META['SERVER_PORT'] = '443'
                form.save(
                    request= request,
                    use_https=True,
                    from_email="[email protected]", 
                        email_template_name='registration/password_reset_email.html')

        except Exception as e:
            logger.warning(str(e))
            continue

    return 'done'
  1. Обычно PasswordResetForm работает с запросом от фронтенда, которого у меня не было. Поэтому я просто создал его.
  2. Когда я следовал примеру в ссылке, это не удалось. Не удалось найти имя сервера в запросе. (Имеет смысл, потому что я создал свой запрос из ниоткуда)
  3. Когда я исправил имя сервера, он запросил порт сервера. Поскольку я использовал https, мой порт — 443, в противном случае используйте порт по умолчанию.
  4. Если вы используете https, не забудьте указать его при сохранении формы use_https=True
person chabislav    schedule 06.05.2015
comment
вместо создания запроса вы также можете просто установить domain_override в form.save() на то, что вы хотите отображать в качестве своего домена в электронном письме сброса (это будет использоваться как для ссылки, так и для темы электронного письма по умолчанию) - person Fasand; 30.07.2019

Я счел полезным обернуть ответ @chabislav в настраиваемую команду управления, которую затем можно повторно использовать по мере необходимости. Обратите внимание, что я исключил фильтр пользовательских объектов, так как знал, что хочу отправить инструкции по сбросу пароля всем пользователям.

# myproject/myapp/management/commands/send_password_reset_emails.py
from django.core.management.base import BaseCommand, CommandError
# I use a custom user model, so importing that rather than the standard django.contrib.auth.models
from users.models import User
from django.http import HttpRequest
from django.contrib.auth.forms import PasswordResetForm


class Command(BaseCommand):
    help = 'Emails password reset instructions to all users'

    def handle(self, *args, **kwargs):
        users = User.objects.all()
        for user in users:
            try:
                if user.email:
                    print("Sending email for to this email:", user.email)
                    form = PasswordResetForm({'email': user.email})
                    assert form.is_valid()
                    request = HttpRequest()
                    request.META['SERVER_NAME'] = 'www.example.com'
                    request.META['SERVER_PORT'] = 443
                    form.save(
                        request= request,
                        use_https=True,
                        from_email="[email protected]", 
                        email_template_name='registration/password_reset_email.html'
                        )
            except Exception as e:
                print(e)
                continue

        return 'done'

Затем это можно легко запустить с помощью python manage.py send_password_reset_emails.

Обратите внимание, что я получил сообщение об ошибке (550, b'5.7.1 Relaying denied'), которое оказалось проблемой из-за того, как был настроен мой почтовый сервер localhost, но как только это было очищено, это сработало довольно хорошо. Наличие его в команде управления также хорошо, потому что оно не засоряет код, который вы используете на регулярной основе (представления).

person pencerw    schedule 10.09.2019