Django configuration to send email - django

Some facts:
I am working on localhost with devserver. I have a Django project where the email sending works perfectly. I set up a new Django project, both 1.4.5, I copy / paste the email settings form the working project (EMAIL_HOST, EMAIL_PORT...) in settings.py to the new one, I open a shell with manage.py and load send_mail from django.core.mail on the first project it can send emails (I receive them in my email client), on the second the email never gets sent. I tried with various servers, gmail and gandi. I tried directly with the smtplib in pure Python code and it works with the same settings. While sending the mail with the first project and with smtplib I can see the function takes a few seconds to return the prompt in the command line but with the second project it returns the prompt immediately which makes me think nothing is happening.
So my question is what could be wrong in my new project's config? Where to look? And if possible how to debug that? (the send_mail function only returns 1, which is the number of mails I have sent, is there a way to get a trace back or some useful error message?)

to answer one of your questions:
>>> how to debug that?
Use pdb.set_trace() just before the call to whatever you want to debug.

I knew it was easy, it had to be a setting and indeed it was. I don't where that one comes from, may be it appears by default in new django projects, I have no idea but I had
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
in my settings file, far from my email settings and I had never entered it myself. Changing it to SMTP or commenting it makes Django actually send the email.

Related

django send_mail has insecure link to http://dpaste.com/

I am trying to send emails with django and for that I use send_email from django.core.mail, but it has a link to http://dpaste.com/, with HTTP and my website is in HTTPS.
This is the message I get in my console:
Mixed Content: The page at 'https://b...' was loaded over a secure connection, but contains a form that targets an insecure endpoint 'http://dpaste.com/'. This endpoint should be made available over a secure connection.
It means that the standard send_mail from django blocks my secure connection? How can that be possible? What othe solutions do I have to send email with django?
Thanks
The problem was happening because I had DEBUG: TRUE and there was an error in the code. Therefor, django was using dpaste to throw the error.
The solution was to turn the DEBUG off or fix the error in the code.
Thanks, Suresh, for helping me on that.

Get 400 (empty response) when sending multi-part form to django

I'm working on an existing Django app and need to be able to upload a file.
I'm sending it a multi-part form so I can send a file and some fields, but the server I get back a 400, but the server errors silently and keeps running.
How can I allow my view to accept a multi-part form?
My route function definition is simply:
#api_view(['POST'])
def upload(request, pk)
print "hello"
It doesn't get to hello, so somewhere in the magical box of Django this JSON error is occuring. Can anyone give me a clue where to look? I've checked our urls.py file and see nothing that would make this decision or interrupt a request and our init.py file is empty. runserver isn't even a file... I guess it's just more django magic.
(Python: 2.7, Django: 1.10.6)
I was sending the request with a Content-Type header as form multipart, once I removed that header my request was being accepted again.
When I removed the header, a boundary field was added to content-type and I suppose that was necessary for Django to not fail silently.
I'm still not sure why Django failed silently.

How to pipe an email into Django?

I'm part of a two-man business selling LED glow toys and one aspect of this is handling support requests. I have a server running exim4 and DJango and have email working so that if a user sends an email to support#myhost.com I'm able to pick up the email and respond.
I'd like to develop something a bit tidier to keep track of the email chain for a particular support request.
To do this, I was thinking of piping the output of my email using a rule in my support email's filter:
pipe /usr/bin/email_to_django_script
What I'm unsure of is how best to go about the last step to actually turning the email content into something DJango can process.
What's the best method to do this? Would a script using curl -d be a sensible option or are there better / less convoluted ways?
You can pipe the output of the email server into a management command. As an example, I have a file /inquiries/management/commands/proc_email.py. I have a single Command class, and the handle() method gets most of the email from the environment, and the body of the email from STDIN:
from_email = strip_tags(os.environ.get('SENDER', None))
to_email = strip_tags(os.environ.get('RECIPIENT', None))
emailMessage = email.message_from_string(''.join(sys.stdin.readlines()))
There is other code in there, but that is how I get the important bits out of it. You can then pipe this into your ORM objects, and access it from the website at some later time.
This is then accessed through /path/to/project/manage.py proc_email.
Depending on your email server, you can also use plus addressing to insure replies come back to the same address. For example, I have my Reply-To headers set to inquiry+12345#whatever.com. The mail server (postfix) then dumps this into the environment under EXTENSION. If no number is supplied, I simply create a new Inquiry, instead of attaching to an existing one.
Not exactly a pure Django solution but I would recommend taking a look at Lamson Project. It's an email server written in Python that you can use to build email applications like what you are describing. I can also integrate with the Django ORM. http://lamsonproject.org/docs/hooking_into_django.html

django-paypal does not receive ipn signal

I am trying to use django-paypal. I was following what was mentioned in
Jay on Django
Here is what i did...
##in my view.py file
def ask_payment(request):
# What you want the button to do.
paypal_dict = {
"business": settings.PAYPAL_RECEIVER_EMAIL,
"amount": "0.10",
"item_name": "book",
"invoice": "yong138peng",
"notify_url": "http://127.0.0.1:8000/accounts/my-ipn-location/",
"return_url": "http://127.0.0.1:8000/accounts/my-return-location/",
"cancel_return": "http://127.0.0.1:8000/accounts/my-cancel-location/",
}
# Create the instance.
form = PayPalPaymentsForm(initial=paypal_dict)
context = {"PP_form": form}
return render_to_response("paypal/payment.html",{'PP_form':form},context_instance=RequestContext(request))
#csrf_exempt
def payment_status(request,status):
return render_to_response("paypal/payment_status.html",
{'status':status},context_instance=RequestContext(request))
##then in my urls.py file
(r'^askforpayment/$','coltrane.views.ask_payment'),
(r'^my-ipn-location/', include('paypal.standard.ipn.urls')),
(r'^my-return-location/$','coltrane.views.payment_status',{'status':'success'}),
(r'^my-cancel-location/$','coltrane.views.payment_status',{'status':'cancel'}),
##in my models.py
def show_me_the_money(sender, **kwargs):
ipn_obj = sender
print "payment was successful!"
# Undertake some action depending upon `ipn_obj`.
if ipn_obj.custom == "Upgrade all users!": ## what is this for, this is sent by paypal??
Users.objects.update(paid=True)
payment_was_successful.connect(show_me_the_money)
My question are:
According to jay on django, i have to put a #csrf_exempt before paypay.standard.ipn.views.ipn function to avoid django complaining about the #csrf_token problem. I did it but i still facing the same problem. Then i put the #csrf_exempt before my return url view function, in this case the payment_status(request,status), the the csrf_token problem is gone. So I am not sure why it is the case.
what is this statement in the signal handler are for?
"if ipn_obj.custom == "Upgrade all users!": .... "
Is this coming from paypay? What are the possible value besides the "Upgrade all users?"
I manage to do the purchase and complete the whole payment process at sandbox. But now the problem is that the paypal does not post the IPN back to my notify_url which is a localhost. I read from Paypal Sandbox IPN Problem that i cannot use localhost (http://127.0.0.1:8000) to test IPN. Then what are the steps needed to test? I don't understand the solution provided in that post. Can someone teach me how to test IPN without deploying the real production server?
Regarding your third point, as Daniel says in the answer to the question you linked, you need to allow Paypal to POST to your local machine. That means you need to open the port 80 on your router and forward the request to your development machine on port 8000. Go to http://whatismyip.com, get the IP and try to access it in your browser. Unless you have your router configured correctly you'll get nothing.
Once you've got your router set up you'll need to run the django server with:
python manage.py runserver 0.0.0.0:8000
Then you'll be able to access it externally. You can test this by putting your Internet connection's IP into the browser - you should see your Django site. If you don't then Paypal can't 'see' you either and will never be able to post back.
I was stuck on this problem for a very long time! Turns out I had an error in my signals code but the error was never displayed, just appeared as though the signal was not being called. Eventually tracked it down by modifying the code in paypal-django like this:
in paypal.standard.ipn.views.py - 3 lines from the bottom:
try:
ipn_obj.verify(item_check_callable)
except:
import sys, traceback
traceback.print_exc(file=sys.stdout)
Then check the apache error log for any errors.
For #1 -- The only place I needed to put the #csrf_exempt tag was on the view that is called by the return_url. PayPal actually posts a lot of data about the payment to this url as well, for whatever reason.
For #2 -- You can specify a "custom" field in the paypal_dict, which will then be passed back to the notify_url. If you're only selling from one url or endpoint, it will be obvious what the payment is for, in combination with the invoice you have specified. But you might want to provide an additional field here to work with. "Upgrade all users!" is just a random example that the django-paypal documentation has.
For #3 -- I used ngrok, as mentioned in the django-paypal docs now (http://django-paypal.readthedocs.org/en/stable/standard/ipn.html#testing). I found it pretty easy to set up, not knowing anything about the tool before-hand.
Additionally -- one gotcha on the postbacks that nailed me for awhile was the following: I believed that PayPal was not posting to my notify_url, and I was researching answers like this.
Eventually I realized that PayPal was actually posting to my notify_url, but that my local machine was using an old version of SSL which would not complete a handshake when posting back to the PayPal sandbox (to get the VERIFIED/INVALID result). My version was 0.9.8 and they need something 1.0 or above. To make a long story short, the notify_url is a multi-step process and the problem could be something besides PayPal making the initial post to the notify_url.

Django Email backend (keeps sending email from incorrect "sender")

I have several instances in my project where I attempt to send an email within a Django view.
I want to be able to hardcode the email sender within the view. When I try to do so, though, it continues to send the emails from the default account specified in my settings file.
Here is an example:
if testform.is_valid():
beta=testform.save()
subject="Hi Beta Tester"
sender="correct#email.com"
recipient=[testform.cleaned_data['email']]
text=loader.get_template('registration/beta_email.txt')
html=loader.get_template('registration/beta_email.html')
site_name='mysite'
d=Context({'site_name':site_name})
text_content=text.render(d)
html_content=html.render(d)
#This sends two mail versions, plain text and html
msg=EmailMultiAlternatives(subject, text_content, sender, recipient)
msg.attach_alternative(html_content, "text/html")
msg.send()
return HttpResponseRedirect('/splash/')
I thought that I could send specify the sender argument explicitly here. And, yet, when I test it, the email is being sent from the address listed in my settings file, configured as the following:
EMAIL_USE_TLS=True
EMAIL_HOST='smtp.gmail.com'
EMAIL_HOST_USER='wrong#email.com'
EMAIL_HOST_PASSWORD='private'
DEFAULT_FROM_EMAIL='wrong#email.com'
Do I just have to remove the DEFAULT_FROM_EMAIL constant to make it work? I tried doing so and it seems to be working but I'm confused. In the Django documentation, it suggests that setting sender in the view should override the DEFAULT.
I've finally figured out the issue here. Unfortunately, gmail rewrites the from and the
envelope on authenticated smtp.
If you want to get around that, you have to use a third party mail server (which doesn't act like such a prissy) and then send mail to gmail users.
For the sender e-mail try putting it in < > and you can add a name:
sender = "Formal Name <correct#email.com>"
that is exactly the syntax I have in my e-mail sending view and it works.
There really shouldn't be a reason that adding the name to it would change how it's sending, but it may be worth trying and perhaps you want an easily readable name anyway.