Django send_mail method : Include session userid in mail message - django

I was able to use send_mail method and it works without any problem.
What I am trying to achieve is to include session's username in mail message.
My views.py allow a certain authenticated user to create numbers. On successful addition of numbers, an email is triggered to the administrators, which at the moment does not include user's userid. So the administrators have no way of knowing which user created the numbers.
My attempt to get userid displayed in mail body below. I also tried another variant -
#send mail
subject= 'Numbers created by {request.user}'
message = 'This user {request.user} has created numbers. '
from_email= settings.EMAIL_HOST_USER
to_list = [settings.EMAIL_ADMIN]

Thanks #MohitC, I did miss f string format and plus, I was incorrectly using ```request.user method. username = request.user
subject= f" Numbers created by {username}"

Related

How can i send a webook to my django app and only execute it on logged in user

Hi i am new to coding and only been learning python and django for about a week. so sorry if this does not make sense.
i am trying to send a webhook(this is just a test then ill add json)
so that when i send to http://127.0.0.1:8000/webhook
i am using postmen desktop so i receive the webhooks.
it will execute my session code but the problem i have that in my app i have
already set up users db and when i sent the webhook it return none since no one seems to be logged in. i know i will have to add a code something like a token to specify each user but only want to test with one user first.
i get the error None or when i remove user authenticated then it says i can't send to anonymous user. is there a way i can send it to lets say a specific user or ID or let's say a token i save with the user.
#csrf_exempt
def webhook(request):
#get current users keys
if request.user.is_authenticated:
user = request.user
database = Bybitapidatas.objects.all().filter(user=user)
for apikey in database:
apikey = apikey.apikey
for apisecret in database:
apisecret = apisecret.apisecret
session = HTTP(endpoint='https://api-testnet.bybit.com/', api_key=apikey, api_secret=apisecret,spot=True)
print(session.place_active_order(
symbol="BTCUSDT",
side="Buy",
type="MARKET",
qty="20",
timeInForce="GTC"
))

Django REST Framework User Registration Privacy Issue: Looking for best practice to not show exception if user with given email exists already

I am suprised I have not found anything on the web regarding the following issue which I thought should be common? I may just have used the wrong search terms so I am happy to receive links with more info.
My problem is that when using ACCOUNT_EMAIL_VERIFICATION = 'mandatory' I want to not give a clue to any user except the owner of an email address whether that mail is registered on my website, i. e. not show a "A user is already registered with this e-mail address." if an existing email is entered.
My assumption is that that would require for the registration endpoint to return the same response independent of whether the email exists or not. I see several possible approaches, but none seems to be a good one:
Use a custom exception handler to remove the exception in question from the error messages sent. That means I have to somehow identify the abovementioned exception among all error messages sent so I can still keep the others in the response. I guess I have to identify the exception message by a string the actual error message (possibly dependent on language settings?). If there are multiple error messages I can simply remove the one in question. But if the exception is the only exception I'd have to fake the same response that would be given after successful creation of a user. That sounds fiddly and not robust to me.
Check uniqueness before is_valid() is called and fake a successful response. But then I won't be able to return exceptions from possible additions errors.
Remove the unique-contraint from the DB so that the is_valid() method does not raise an error and prevent the instance from saving in perform_create(). But I don't really want to remove that database-level protection layer.
There must be a better solution out there I hope?
Appreciate any help!
Mike
You should change the error/validation message to be more generic, for example:
Email address error.
It is very similar situation as in login. You don't write explicitly that the email address doesn't exist or the password is too short, you just send a message:
Invalid email or password.
Additionally, you can add information that if the problem repeats please contact to system/service administrator. Then if a person contacts the administrator from his/her email problem can be fixed manually.
Solution with generating unique email address might be too complex and can bring unexpected problems. What if the user just forgot about the old account and recreate the new account, with loss of previous account's data.
I came up with a possible solution today. Seems to be a little improvised but avoids the abovementioned problems. Would be happy to hear your thoughts or suggestions.
The approach was to override the create method and if it fails to the uniqueness constraint generate a pseudo serializer instance with a modified email address that would be unique and only return errors from that pseudo instance.
Additionally, the entire create request only returns an HTTP 200 OK status, independent of whether a user was created or if a user with that mail existed.
#custom create method to not return "email exists" error to user if email exists
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
try: #try if data is valid. If so, create user.
serializer.is_valid(raise_exception=True)
user = self.perform_create(serializer)
print('User created:')
print(user)
except ValidationError as err: #if Validation error was returned
email = request.data['email']
email = get_adapter().clean_email(email)
# check if one issue was due to existing email
if allauth_settings.UNIQUE_EMAIL and email and email_address_exists(email):
# generate unique version of the mail address by appending string to local part to revalidate with unique mail address
provisional_email = make_email_unique(email, uniqueness_validator=email_address_exists)
# create fake request.data dict with unique mail address
provisional_request_data = request.data.copy()
provisional_request_data['email'] = provisional_email
#get new serializer with new request.data
provisional_serializer = self.get_serializer(data=provisional_request_data)
#check if data was valid if email was unique
try:
provisional_serializer.is_valid(raise_exception=True)
# get user who owns original email from request
user = get_user_from_email(request.data['email'])
except ValidationError as err2:
# else validate again, this time return any errors that may occur even with unique email
raise err2
else: #if error was not (also) due to existing mail problem raise validation errrors
raise err
headers = self.get_success_headers(serializer.data)
# always return 200 OK if no error is shown (i. e. no 201 CREATED that could hint to an existing mail address)
return Response(status=status.HTTP_200_OK,
headers=headers)

Sending Bulk email in Django

I have to send bulk email in django, the email template will be will be customized and the some data in the template will be coming from db. i twas using django notification but it can only send email to the registered users. I have to send emails to the non-registered users. there will be five email template the user can select any one and the email has to be sent.
For ex. An invitation to the event to the group of non-registered users. user will enter email ids, and will do a bulk send. which django package can i use to achieve the same.
You can use django's default sending multiple email system. From here: https://docs.djangoproject.com/en/dev/topics/email/#sending-multiple-emails
You can try like this:
from django.core import mail
connection = mail.get_connection()
connection.open()
reciever_list= ['aa#bb.cc', 'dd#ee.ff'] #extend this list according to your requirement
email1 = mail.EmailMessage('Hello', 'Body goes here', 'from#example.com',
reciever_list, connection=connection)
email1.send()
connection.close()
For bulk email reference, you can check this so answer: How does one send an email to 10,000 users in Django?
Edit
From this stackoverflow answer, you can send emails with template. If you use django 1.7, html_message can be added as perameter of send_mail(). Details here.
By the way, for mass email handling, django has send_mass_mail() method.

sending activation emails-Django

I am creating an inactive user and want to send them email for activating there accounts like the one django-registration send when we create an account.
This is my views.py
user = User.objects.create_user(userName, userMail,userPass)
user.is_active=False
user.save()
You should review the topical guide on sending emails. Basically, you'll just use the components from django.core.mail to send an activation email with all the necessary information after you've created the user instance.
It's important that that email contains further information on how the user is supposed to activate their account. The way django-registration does it is that it has a separate model associated with the User instance that specified a unique identifier which would be used in the activation view to identify which user account is supposed to be activated, i.e. creating a GET request to http://foo/accounts/activate/550e8400-e29b-41d4-a716-446655440000 would activate the user account with the associated UUID.
There are some other intricate details that make django-registration a thorough and well-polished solution, in spite of being a bit dated (i.e. no class-based views), so I second #NCao in suggesting that you take enough time to review the sources from the official repository and ripoff and duplicate all the necessary bits.
Basically after a user signed up, you want to set user.is_active=False.
Then you send an URL with the user's information(for example, id) to the user's email.
When the user click the link, it will trigger an activation function. Within the activation function, it firstly extracts the user's information based on the URL (id). Then you can query the user object by calling user.objects.get(id=id). After that, you can set user.is_active=True and save user.
Here is the code to send email:
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
fromaddr='your email address' #(Gmail here)
username='your user name'
password='your password'
def send_email(toaddr,id):
text = "Hi!\nHow are you?\nHere is the link to activate your
account:\nhttp://127.0.0.1:8000/register_activate/activation/?id=%s" %(id)
part1 = MIMEText(text, 'plain')
msg = MIMEMultipart('alternative')
msg.attach(part1)
subject="Activate your account "
msg="""\From: %s\nTo: %s\nSubject: %s\n\n%s""" % (fromaddr,toaddr,subject,msg.as_string())
#Use gmail's smtp server to send email. However, you need to turn on the setting "lesssecureapps" following this link:
#https://www.google.com/settings/security/lesssecureapps
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
server.login(username,password)
server.sendmail(fromaddr,[toaddr],msg)
server.quit()
You may also want to check this out: https://github.com/JunyiJ/django-register-activate
Hope it helps!

Control a function (E.g send mail) from a users profile page

I have a profile page like so: http://i.stack.imgur.com/Rx4kg.png . In management I would like a option "Notify by mail" that would control my send_email functions in every application I want. As example I'm using django-messages and it sends private messages aswell as emails when you send a message. I would like for the user to be able to specify if he wants emails aswell when he gets a message.
messages/utils.py
def new_message_email(sender, instance, signal,
subject_prefix=_(u'New Message: %(subject)s'),
template_name="messages/new_message.html",
default_protocol=None,
*args, **kwargs):
"""
This function sends an email and is called via Django's signal framework.
Optional arguments:
``template_name``: the template to use
``subject_prefix``: prefix for the email subject.
``default_protocol``: default protocol in site URL passed to template
"""
if default_protocol is None:
default_protocol = getattr(settings, 'DEFAULT_HTTP_PROTOCOL', 'http')
if 'created' in kwargs and kwargs['created']:
try:
current_domain = Site.objects.get_current().domain
subject = subject_prefix % {'subject': instance.subject}
message = render_to_string(template_name, {
'site_url': '%s://%s' % (default_protocol, current_domain),
'message': instance,
})
if instance.recipient.email != "":
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL,
[instance.recipient.email,])
except Exception, e:
#print e
pass #fail silently
Apparently instance.recipient.email is the email for the recipient user. So my questions are: How do I go about creating an option in my profile management that can be used in my new_message_email to check if the user wants emails or not? My own thoughts are that I need to save a value in the database for the user and then check for that value in new_message_email function. How I do that isn't clear though. Do I create a new function in my userprofile/views.py and class in userprofile/forms.py? And have my userprofile/overview.html template change them? Some specifics and thoughts if this is the right approach would help alot!
You probably want to start off by creating a user profile so that you have a good way to store weather or not the user wants these emails sent to them. This is done using the AUTH_PROFILE_MODULE setting in your settings.py.
Once you have the data stored, you should be able to access it from instance.recipient (assuming that instance.recipient is a User object). So you could change your code to:
if instance.recipient.get_profile().wants_emails and instance.recipient.email != "":
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL,
[instance.recipient.email,])
Done and done.