Hello I am trying to create password reset view in Django. I have set up the mail backend and urls and templates. Everything looks fine but when I try to send mail to reset password Django is sending multiple emails. For example 7 or 11 password reset email at the same time. How can I make it just one email for each time.
Thanks a lot
This is What I did:
setting.py:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST_USER = "my_email"
EMAIL_HOST_PASSWORD = "my_password"
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
urls.py
path('password-reset/',
auth_views.PasswordResetView.as_view(template_name='accounts/password_reset.html'),
name='password_reset'),
path('password-reset/done/',
auth_views.PasswordResetDoneView.as_view(template_name='accounts/password_reset_done.html'),
name='password_reset_done'),
path('password-set-confirm/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(template_name='accounts/password_reset_confirm.html'),
name='password_reset_confirm'),
path('password-set-complete/',
auth_views.PasswordResetCompleteView.as_view(template_name='accounts/password_reset_complete.html'),
name='password_reset_complete'),
Also, I set the templates for each view.
IF this is still a problem... If you have multiple "test users" and you created them with the same email address that is probably causing your problme
It sometimes helps to check the Django source code itself, so always dive into that if you don't understand what's happening.
If you look at PasswordResetForm's save() method in django.contrib.auth.forms, you'll see that it loops through self.get_users(email) and then sends one (and only one) email for each user.
So the only way multiple emails can be sent is if there are multiple users with the same email.
I don't think their is any setting for the same you may be end up calling same URL multiple time might be a logic issue.
Try to use debug mode or with the help of print statements.
PasswordResetForm has get_users() method which returns all active usernames in an email. We can overwrite that method to return just 1 user which is passed to it. This way password reset email will be sent to only 1 user that we choose.
from django.contrib.auth.forms import PasswordResetForm
class MyPasswordResetFormSpecificUser(PasswordResetForm):
"""
Send password reset email to specific user and not all active
users in an email.
"""
user = None
def get_users(self, email):
"""
Instead of getting all users in an email,
just sent the user that we want to reset password for.
"""
return [self.user]
Then you can use this new form class into your views as shown below:
email = 'your email here'
form = MyPasswordResetFormSpecificUser({'email': email})
assert form.is_valid()
form.user = 'User object who needs password reset'
# use https only when running on GAE
form.save(
request=self.request,
use_https=False # True if you are deploying to https url
)
Related
So I've been working on this blog website and I wanted to add a form so that users can contact the blog admin. However when they fill out the form and send email.. The email I receive is from myself and not from the user. Someone Please help me to fix it.
The form is working correctly and message-email does return the email that they enter.
e.g. lets say in my form I add a user email as example1#example.com
but when I recieve an email it's not coming from example1#example.com but from my host email myemail#gmail.com.
views.py:
def contact(request):
if request.method == 'POST':
message_name = request.POST['message-name']
message_email = request.POST['message-email']
message = request.POST['message']
#send mail
send_mail(
'message from ' + message_name + ' their email ' + message_email ,
message,
message_email,
['myemail#gmail.com'],
)
return render(request, 'blog/contact.html', {'message_name':message_name})
settings.py:
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_POST = 587
EMAIL_HOST_USER = 'myemail#gmail.com'
EMAIL_HOST_PASSWORD = '******'
EMAIL_USE_TLS = True
This may have some useful information.
https://www.digitalocean.com/community/tutorials/how-to-use-google-s-smtp-server
Note: Google will automatically rewrite the From line of any email you
send via its SMTP server to the default email address associated with
the account if the one used is not on the Send mail as addresses list
in Gmail or G Suite settings. You can verify the list by going to the
Accounts and Import tab on the settings screen.
You need to be aware of this nuance because it affects the
presentation of your email, from the point of view of the recipient,
and it may also affect the Reply To setting of some programs.
I'm working on a project hosted on Google App Engine, and using Django-allauth for my user system.
Right now I'm just using the following setup in settings.py
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = DEFAULT_FROM_EMAIL = 'myMail#gmail.com'
EMAIL_HOST_PASSWORD = 'password'
But I would like to use GAE's Mail API instead, so that I can take use of all the quotas available.
To send an email with GAE's API I can do as follows:
sender_address = "myMail#gmail.com"
subject = "Subject"
body = "Body."
user_address = "user#gmail.com"
mail.send_mail(sender_address, user_address, subject, body)
As I understand it from the allauth documentation, I can "hook up your own custom mechanism by overriding the send_mail method of the account adapter (allauth.account.adapter.DefaultAccountAdapter)."
But I'm really confusing about how to go about doing this.
Does it matter where I place the overridden function?
Any additional tips would be greatly appreciated.
My Solution
What I did to get Django-allauth email system to work with Google App Engine mail API
Created a file auth.py in my 'Home' app:
from allauth.account.adapter import DefaultAccountAdapter
from google.appengine.api import mail
class MyAccountAdapter(DefaultAccountAdapter):
def send_mail(self, template_prefix, email, context):
msg = self.render_mail(template_prefix, email, context)
sender_address = "myEmailAddress#gmail.com"
subject = msg.subject
body = msg.body
user_address = email
mail.send_mail(sender_address, user_address, subject, body)
In order to use your email as sender with GAE's mail API, it is important to remember to authorize the email as a sender
Lastly, as e4c5 pointed out, allauth has to know that this override exists, which is done as so in settings.py
ACCOUNT_ADAPTER = 'home.auth.MyAccountAdapter'
You have to tell django-allauth about your custom adapter by adding the following line to settings.py
ACCOUNT_ADAPTER = 'my_app.MyAccountAdapter'
taking care to replace my_app with the correct name
I am trying to implement password reset functionality.
My urls contains:
url(r'^password_reset/$','django.contrib.auth.views.password_reset', {'template_name': 'resetpassword.html', 'post_reset_redirect' : '/password_reset/mailed/'},
name="password_reset"),
url(r'^password_reset/mailed/$',
'django.contrib.auth.views.password_reset_done',{'template_name': 'resetpassword_mailed.html'}),
url(r'^password_reset/(?P<uidb36>[0-9A-Za-z]{1,13})-(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
'django.contrib.auth.views.password_reset_confirm',
{'post_reset_redirect' : '/password_reset/complete/'}),
url(r'^password_reset/complete/$',
'django.contrib.auth.views.password_reset_complete',{'template_name': 'resetpassword_complete.html'}),
and settings.py:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.mail.ru'
EMAIL_HOST_USER = 'noreply#mysite.com'
DEFAULT_FROM_EMAIL = 'noreply#mysite.com'
EMAIL_HOST_PASSWORD = 'password'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
URL routing works just fine, however email are not being sent.
If I try to use Django shell and test sending:
email = EmailMessage('Subject', 'Body', to=['test#email.com'])
email.send()
And it works just fine as well.
How could I fix this? I don't get any error messages and don't know how could I debug this.
UPD
I have found out that in django/contrib/auth/views.py: password_reset method I always go to
else:
post_reset_redirect = resolve_url(post_reset_redirect)
part and never to actually sending email. How's that?
if post_reset_redirect is None:
post_reset_redirect = reverse('password_reset_done')
else:
post_reset_redirect = resolve_url(post_reset_redirect)
if request.method == "POST":
form = password_reset_form(request.POST)
if form.is_valid():
print 'reset form valid'
opts = {
'use_https': request.is_secure(),
'token_generator': token_generator,
'from_email': from_email,
'email_template_name': email_template_name,
'subject_template_name': subject_template_name,
'request': request,
'html_email_template_name': html_email_template_name,
}
if is_admin_site:
opts = dict(opts, domain_override=request.get_host())
form.save(**opts)
return HttpResponseRedirect(post_reset_redirect)
If the user has no password (e.g. created with create_user()), the password reset won't send anything! Make sure you create a password as well via:
password = User.objects.make_random_password()
Then, you also need to set the password and save, for example
user.set_password(password)
user.save()
Could be a trivial question but the user you are using to test has a valid email set? If it's empty will not send the email neither raise an exception.
Check the send method source code.
Other way to see if the email is being generated is use the console backend:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
and look at the console because the email should appears there.
Thanks
I am having difficulties in configuring my settings.py so that I can send email from a webserver with any sender name
This is what I have done:
EMAIL_USE_TLS = True
EMAIL_HOST = 'mail.wservices.ch'
HOSTNAME = 'localhost'
DEFAULT_FROM_EMAIL = 'info#domain.com'
And sending email like this:
html_content = render_to_string('htmlmail.html', {})
text_content = strip_tags(html_content)
msg = EmailMultiAlternatives('subject!',text_content,'info#domain.com',['to#domain.com'])
msg.attach_alternative(html_content, "text/html")
msg.send()
But I am getting:
{('to#domain.com': (554, '5.7.1 <to#domain.com>: Relay access denied')}
In one function, I have two msg.send() calls, BTW.
What am I doing wrong?
this is the answer webmaster when i asked how to send mails from webserver programmatically:
It is possible to send mails from E-Mail-Server "mail.wservices.ch".I suggest to
use the local installed Mail-Server. Hostname: localhost
There you can set any sender name, they just have to exist.
https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email
Make sure first you have properly install django-sendmail
$ sudo apt-get install sendmail
in the settings.py :
from django.core.mail import send_mail
DEFAULT_FROM_EMAIL='webmaster#localhost'
SERVER_EMAIL='root#localhost'
EMAIL_HOST = 'localhost'
EMAIL_HOST_USER=''
EMAIL_BACKEND ='django.core.mail.backends.smtp.EmailBackend'
EMAIL_PORT = 25 #587
EMAIL_USE_TLS = False
in views.py:
from project.apps.contact import ContactForm
def contactnote(request):
if request.method=='POST':
form =ContactForm(request.POST)
if form.is_valid():
topic=form.cleaned_data['topic']
message=form.cleaned_data['message']
sender=form.cleaned_data.get('sender','email_address')
send_mail(
topic,
message,
sender,
['myaddress#gmail.com'],fail_silently=False
)
#return HttpResponseRedirect(reverse('games.views.thanks', {},RequestContext(request)))
return render_to_response('contact/thanks.html', {},RequestContext(request)) #good for the reverse method
else:
form=ContactForm()
return render_to_response('contact.html',{'form':form},RequestContext(request))
contact.py:
from django import forms as forms
from django.forms import Form
TOPIC_CHOICES=(
('general', 'General enquiry'),
('Gamebling problem','Gamebling problem'),
('suggestion','Suggestion'),
)
class ContactForm(forms.Form):
topic=forms.ChoiceField(choices=TOPIC_CHOICES)
sender=forms.EmailField(required=False)
message=forms.CharField(widget=forms.Textarea)
#the widget here would specify a form with a comment that uses a larger Textarea widget, rather than the default TextInput widget.
def clean_message(self):
message=self.cleaned_data.get('message','')
num_words=len(message.split())
if num_words <4:
raise forms.ValidationError("Not enough words!")
return message
Try it , this is a whole working example apps, modify it
to be send to to mailserver like a reply when it got an mail, very simple to modify it
I am using the Gmail SMTP server to send out emails from users of my website.
These are the default settings in my settings.py
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'example#example.com'
EMAIL_HOST_PASSWORD = 'pwd'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
SERVER_EMAIL = EMAIL_HOST_USER
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
If I want a user to send an email, I am overriding these settings and sending the email using Django's email sending methods. When an exception occurs in the system, I receive an email from the example#example.com. Sometimes I receive an email from some logged in user. Which could also possibly mean that when a user receives an email sent from my website it has a sent address different from the actual user.
What should be done to avoid this situation?
Django only uses settings.DEFAULT_FROM_EMAIL when any of the mail sending functions pass None or empty string as the sender address. This can be verified in django/core/mail.py.
When there is an unhandled exception Django calls the mail_admins() function in django/core/mail.py which always uses settings.SERVER_EMAIL and is only sent to addresses listed in settings.ADMINS. This can also be verified in django/core/mail.py.
The only other place Django itself sends e-mails is if settings.SEND_BROKEN_LINK_EMAILS is True, then CommonMiddleware will send mail to all addresses listed in settings.MANAGERS and the e-mail sender is settings.SERVER_EMAIL.
Therefore, the only time a regular user will receive e-mail from your site is when you call send_mail(). So, always pass a real address as the from_mail argument and you will avoid users receiving email from settings.SERVER_EMAIL or settings.DEFAULT_FROM_EMAIL.
Side note: django-registration is at least one example of a Django pluggable that will send mail from settings.DEFAULT_FROM_EMAIL so in cases like this you need to make sure it is a proper e-mail address such as support#yoursite.com or webmaster#yoursite.com.