Im using Django, anymail API & mailgun to send emails from my site.
I have a form where users can subscribe,
At present when the email is send to the subscriber's email address, the FROM address default to a combination of their and my email domain.
As an exmample:
User enters test#test.com an receives email from test=test.com#mail.mydomain.com and not the one I specified of info#mydomain.com
I am pretty sure the problem is within my views.py, but im not sure how to resolve.
views.py
def send_email(subject, html_content, text_content=None, from_email=None, recipients=[], attachments=[], bcc=[], cc=[]):
# send email to user with attachment
if not from_email:
from_email = settings.DEFAULT_FROM_EMAIL
if not text_content:
text_content = ''
email = EmailMultiAlternatives(
subject, text_content, from_email, recipients, bcc=bcc, cc=cc
)
email.attach_alternative(html_content, "text/html")
for attachment in attachments:
# Example: email.attach('design.png', img_data, 'image/png')
email.attach(*attachment)
email.send()
def send_mass_mail(data_list):
for data in data_list:
template = data.pop('template')
context = data.pop('context')
html_content = get_rendered_html(template, context)
data.update({'html_content': html_content})
send_email(**data)
# Contact Form - home.html
def HomePage(request, template='home.html'):
form = ContactForm(request.POST or None)
if form.is_valid():
from_email = form.cleaned_data['from_email']
# Create message1 to send to poster
message1 = {
'subject': 'Test',
'from_email': from_email,
'recipients': [from_email],
'template': "marketing/welcome.html",
'context': {
"from_email": from_email,
}
}
# Create message1 to send to website admin
message2 = {
'subject': 'Test - Contact',
'from_email': from_email,
'recipients': ['info#mydomain.com'],
'template': "marketing/admin.html",
'context': {
"from_email": from_email,
}
}
try:
send_mass_mail([message1, message2])
except BadHeaderError:
return HttpResponse('Invalid header found.')
return redirect('/thanks/')
context = {
"form": form,
}
return render(request, template, context)
It looks as if you are using the from_email from the user, not info#mydomain.com. In two places you have:
'from_email': from_email,
Many mail providers will limit the addresses that you can send mail from (to stop you sending spam using someone else's address.
Therefore you can't use a from_email that the user gives you. The usual approach is to use your own address as the from_email, but set a reply-to header so that any replies go to the address that the user specified.
Related
Sorry for asking a basic thing. new to Python and Django ,
I want to resend email if the OTP from PUT request is incorrect.
I have a function which send email with otp automatically on Register.
But if user PUT incorrect OTP I want to resend that email with new otp, So I want to merge sent_email_otp into verifyEmail function.
So how could I achieve that?
#receiver(post_save, sender=CustomUser)
def send_email_otp(sender, instance, created, **kwargs):
if created:
try:
subject = "Your email needs to be verified to use site"
message = f'Hi, Dear {instance.name} use this following OTP to Get verified your email : OTP({instance.otpForEmail})'
email_from = settings.EMAIL_HOST_USER
recipient_list = [instance.email]
send_mail(subject, message, email_from, recipient_list)
print(f"Email Sent to {instance.email}")
except Exception as e:
print(e)
print("Something Wrong at send_email_otp")
#api_view(['PUT'])
#permission_classes([IsAuthenticated])
def verifyEmail(request, pk):
user = CustomUser.objects.get(id=pk)
data = request.data
otp_to_verify = data['otpForEmail']
if otp_to_verify == user.otpForEmail:
user.isEmailVerified = True
user.save()
message = {'detail': 'Your email is now verified'}
return Response(message, status=status.HTTP_400_BAD_REQUEST)
else:
message = {
'detail': 'OTP is not valid and expired, Use New OTP which we have sent you on the email'}
return Response(message, status=status.HTTP_400_BAD_REQUEST)
Edit:
If I simply call the send_email_otp() inside else statement of verifyEmail then this error comes :
TypeError: send_email_otp() missing 3 required positional arguments: 'sender', 'instance', and 'created'
You cant call the signal directly unless you provide it the expected input.
You will need to create another function for sending the otp. and call it in the post_save signal and in the view
def send_otp(name, email, otpForEmail):
subject = "Your email needs to be verified to use site"
message = f'Hi, Dear {name} use this following OTP to Get verified your email : OTP({otpForEmail})'
email_from = settings.EMAIL_HOST_USER
recipient_list = [email]
send_mail(subject, message, email_from, recipient_list)
print(f"Email Sent to {email}")
#receiver(post_save, sender=CustomUser)
def send_email_otp_on_post_save(sender, instance, created, **kwargs):
if created:
try:
send_otp(instance.name, instance.email, instance.otpForMail)
except Exception as e:
print(e)
print("Something Wrong at send_email_otp")
#api_view(['PUT'])
#permission_classes([IsAuthenticated])
def verifyEmail(request, pk):
user = CustomUser.objects.get(id=pk)
data = request.data
otp_to_verify = data['otpForEmail']
if otp_to_verify == user.otpForEmail:
user.isEmailVerified = True
user.save()
message = {'detail': 'Your email is now verified'}
return Response(message, status=status.HTTP_400_BAD_REQUEST)
else:
message = {
'detail': 'OTP is not valid and expired, Use New OTP which we have sent you on the email'}
send_otp(user.name, user.email, user.otpForEmail)
return Response(message, status=status.HTTP_400_BAD_REQUEST)
It would be hard for you to configure the same function to send_mail again to send OTP, as you said this sends the email when the user gets registered. So why not modify the verifyEmail itself.
First, you don't need a user instance here as the user is already authenticated and you already have the User Id.
So in the else statement of verifyEmail, you can send_email without calling send_email_otp() function.
Update the verifyEmail to.
#api_view(['PUT'])
#permission_classes([IsAuthenticated])
def verifyEmail(request, pk):
user = CustomUser.objects.get(id=pk)
data = request.data
otp_to_verify = data['otpForEmail']
if otp_to_verify == user.otpForEmail:
user.isEmailVerified = True
user.save()
message = {'detail': 'Your email is now verified'}
return Response(message, status=status.HTTP_400_BAD_REQUEST)
else:
subject = "Your email needs to be verified to use site "
message = f'Hi, Dear {user.name} use this following OTP to Get verified your email : OTP({user.otpForEmail})'
email_from = settings.EMAIL_HOST_USER
recipient_list = [user.email]
send_mail(subject, message, email_from, recipient_list)
print(f"Email Sent to {user.email}")
message = {
'detail': 'OTP is not valid and expired, Use New OTP which we have sent you on the email'}
return Response(message, status=status.HTTP_400_BAD_REQUEST)
I'm searching for solution to this problem for many hours but can't find anything related. I want to get user's email from input and send mail from admin to that email address. Here are my codes:
views.py:
def index(request):
context = {
'questions': Question.objects.all(),
'applicants': Applicant.objects.filter(status=1),
'empty_cards': range(4 - Applicant.objects.filter(status=1).count())
}
if request.method == "POST":
if request.POST.get('message_text'):
Message.objects.create(
sender_name = request.POST.get('sender_name'),
sender_email = request.POST.get('sender_email'),
message_text = request.POST.get('message_text'))
if request.method == 'POST':
subject = 'Welcome !'
message = 'We will back to you.'
from_email = settings.EMAIL_HOST_USER
recipient_list = 'don't know how to get email'
send_mail(subject, message, from_email, recipient_list)
return render(request, 'index.html', context)
from your code I assume that you already have access to the user's mail
inside the request.
so you can try this:
sender_email = sender_request.POST.get('sender_email')
recipient_list = [sender_email]
i am using Ngrok to run my website with https://, and when i send an activation email to myself, instead of seeing 'https://something.ngrok.io/...' i get 'http://localhost:8000/...'.
This is the code responsible for sending the Activation Email which - to my opinion - it should send Ngrok's domain not the development domain ...
...
current_site = get_current_site(request)
mail_subject = 'Activate your customer account.'
message = render_to_string('user_register_email/account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
'token': user_token.make_token(user),
})
receiver = form.cleaned_data['email']
email = EmailMessage(
mail_subject, message, to=[receiver]
)
email.send()
messages.info(
request, f'An activation link has been sent to %s' % (receiver))
return redirect('accounts:login')
is it possible ?
current_site.domain returns the value set on the site instance, you can either change it from the admin panel, or you can use request.get_host() instead
I'm trying to send a mail using Django with EmailMultiAlternatives. It works well but in "from" says "info"
Is it posible to say my name for example? How can I do this?
Here is my code:
subject, from_email, to = 'Afiliations', 'info#domain.com', 'other#domain.com'
text_content = 'Afiliation is working.'
t = loader.get_template('emails/afiliados.html')
c = Context({ 'order': order_obj })
html_content = t.render(c)
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()
For the Name to be displayed instead of the username part of the email, just do
from_email = "info#domain.com <info#domain.com>"
OR
from_email = "Name <info#domain.com>"
I sent the following email via Django
subject, from_email, to = 'site Registration', 'support#site.com', self.second_email
text_content = 'Click on link to finish registration'
html_content = '<html><body>Click Here</body></html>'
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()
When I went the the email (google and yahoo email) they both displayed the Click Here text in blue (I assume this means that it's recognized as a link), however, the link is not clickable and does not link to site.com/acc... What am I doing wrong?
Thanks!
You probably need to make it a valid URL: (note the included scheme)
<a href="http://site.com/accounts/user/' + self.slug +'">
I built a helper function to do this, and used render_to_string to use an HTML template to send instead of typing everything out in the function. Here's my function:
def signup_email(username, email, signup_link):
subject, from_email, to = 'Site Registration', settings.DEFAULT_FROM_EMAIL, email
text_content = 'Click on link to finish registration'
html_content = render_to_string('pet/html_email.html', {'username': username, 'signup_link':signup_link})
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
return msg
Then in the views.py just call it:
class OwnerCreateAccount(FormView):
# class based view attributes
def form_valid(self, form):
# other form logic
msg = signup_email(username=username, email=email, signup_link=owner.salt)
msg.send()
return super(OwnerCreateAccount, self).form_valid(form)