I want to send a HTML email to the users after they signup to the website. Earlier I wrote this script to send
from google.appengine.api import mail
message = mail.EmailMessage(sender="Example.com Support <support#example.com>",
subject="Your account has been approved")
message.to = "Albert Johnson <Albert.Johnson#example.com>"
message.body = """
Dear Albert:
Your example.com account has been approved. You can now visit
http://www.example.com/ and sign in using your Google Account to
access new features.
Please let us know if you have any questions.
The example.com Team
"""
message.html = """
<html><head></head><body>
Dear Albert:
Your example.com account has been approved. You can now visit
http://www.example.com/ and sign in using your Google Account to
access new features.
Please let us know if you have any questions.
The example.com Team
</body></html>
"""
message.send()
But instead of placing the HTML directly in the main code, I want to have a separate HTML file which would be used as a body.
I tried to do it as follows:
message.html = 'emailHTML.html'
but in vain. How can I use a HTML file in the place of HTML code?
You can set
message.html = open('emailHTML.html').read()
to get exactly the same effect as what you're doing now; or, you could have the HTML as an attachment (so the email's body is just the plain text one, but the recipient can download the HTML as an attachment) with:
message.attachments = [('emailHTML.html', open('emailHTML.html').read())]
I'm not quite sure what you'd hope to accomplish in either case, but these are pretty much the only two possibilities I can think of. If neither is satisfactory, please edit your Q to explain exactly what you want this email to look like to the user (is the body supposed to be plain or html, is there supposed to be an attachment...?).
Probably the best way to do this would be to use a templating engine to load and generate the HTML as a string from the HTML file. For example, if you use the webapp2 jinja2 extras package, you could do something along the lines of:
from webapp2_extras import jinja2 as webapp_extras_jinja2
# ...
def get_message_html():
jinja2 = webapp_extras_jinja2.get_jinja2()
return jinja2.render_template('relative/path/to/template.html')
# ...
def send_email():
# ...
message.html = get_message_html()
# ...
Note that to get this working, you need to add jinja2 to the libraries section of app.yaml as in:
libraries:
- name: webapp2
version: 2.5.2
- name: jinja2
version: 2.6
... and you also need to include an appropriate 'webapp2_extras.jinja2' to the app config. Ex:
config = {
'webapp2_extras.jinja2': {
'template_path': 'path/containing/my/templates',
'environment_args': {
# Keep generated HTML short
'trim_blocks': True,
'extensions': [
# Support auto-escaping for security
'jinja2.ext.autoescape',
# Handy but might not be needed for you
'jinja2.ext.with_'
# ... other extensions? ...
],
# Auto-escape by default for security
'autoescape': True
},
# .. other configuration options for jinja2 ...
},
# ... other configuration for the app ...
},
# ...
app = webapp2.WSGIApplication(routes, is_debug_enabled, config)
While you can just as easily open the HTML file yourself, the benefit of using a templating engine such as jinja2 is that it will encourage you to compose and reuse the HTML in a more sane way (whereas simply loading the HTML file might result in you eventually applying substitutions by hand). Also, just a quick security reminder: if any of the data you include in the email comes from untrusted sources (like the user or another user), make sure to properly validate and sanity-check the content (and also enable auto-escaping in the templating engine).
You can obviously choose a templating other than jinja2, but I specifically chose that one for my answer since it is well supported and well documented for App Engine.
Related
I am a little stuck with writing a custom authenticator for jupyterhub. Most probably because I do not understand the inner workings of the available REMOTE_USER authenticator. I am not sure if it is applicable in my case... anyhow... this is what I'd like to do:
My general idea: I have a server that authenticates a user with his or her institutional login. After logging into the institution server/website, the users' data are encoded -- only some details to identify the user. They are then redirected to a the jupyterhub domain in the following way
https://<mydomain>/hub/login?data=<here go the encrypted data>
Now, if a request gets sent like this to my jupyterhub-domain, I'd like to decrypt the submitted data, and authenticate the user.
My trial:
I tried it with the following code. But it seems I am too nooby... :D
So please, pedantic comments are welcome :D
from tornado import gen
from jupyterhub.auth import Authenticator
class MyAuthenticator(Authenticator):
login_service = "my service"
authenticator_login_url="authentication url"
#gen.coroutine
def authenticate(self,handler,data=None):
# some verifications go here
# if data is verified the username is returned
My first problem... clicking the button on the login page, doesn't redirect me to my Authentication URL... it seems the variable authenticator_login_url from the login template is set somewhere else...
Second problem... a request made to .../hub/login?data=... is not evaluated by the authenticator (it seems...)
So: Has somebody any hints for me how to go about this?
As you see I followed the tutorials here:
https://universe-docs.readthedocs.io/en/latest/authenticators.html
So the following code does the job, however, I am always open to improvements.
So, what I did was redirect an empty login attempt to the login-url and deny access. If data is presented, check the validity of the data. If verified, user can login.
from tornado import gen, web
from jupyterhub.handlers import BaseHandler
from jupyterhub.auth import Authenticator
class MyAuthenticator(Authenticator):
login_service = "My Service"
#gen.coroutine
def authenticate(self,handler,data=None):
rawd = None
# If we receive no data we redirect to login page
while (rawd is None):
try:
rawd = handler.get_argument("data")
except:
handler.redirect("<The login URL>")
return None
# Do some verification and get the data here.
# Get the data from the parameters send to your hub from the login page, say username, access_token and email. Wrap everythin neatly in a dictionary and return it.
userdict = {"name": username}
userdict["auth_state"] = auth_state = {}
auth_state['access_token'] = verify
auth_state['email'] = email
#return the dictionary
return userdict
Simply add the file to the Python path, so that Jupyterhub is able to find it and make the necessary configurations in your jupyterhub_config.py file.
I'm using the Tornado with python to build a web server. I want to allow users not to type www.
For example, if user types example.com to visit my web page, I want to add www for user. In other words, if user types example.com in his browser and type "Enter", a www will be inserted automatically in front of example.com.
This is my code for now:
application.add_handlers(r"^(www).*", [(r"/$", IndexHandler)])
With the code above, if user visits www.example.com, the class IndexHandler will get the request and render the index page (self.render('/index.html')).
Then I've tried like this:
application.add_handlers(r"^(example).*", [(r"/$", RedirectionHandler)])
class RedirectionHandler(tornado.web.RequestHandler):
def get(self):
self.redirect('www.example.com')
Well, it doesn't work because self.redirect gives me example.com/www.example.com
Do
seft.redirect('http://www.example.com')
In general in any language when you redirect plain text, the system thinks it's a relative url and tries to append/complete the url with the existing hostname in the already typed url (here example.com).
Putting http(s):// at the beginning tells that the address is absolute, so you rewrite all the address from scratch.
editied original question:
Im trying to make a google appengine app which uses the g+ avatar and human name...
...
So it seems that i need the google-api-python-client library in my app.
...
to enable access to the profile scope so i can look up 'me' and grab the users name and avatar and chuck them in a couple of properties in my user objects (with a button to reload the values again or something).
So has anyone does this? Or has a working example (or even a pointer to which of the ways to authorise my app for scope=[profile])?
Discoveries:
I dont need the google-api-python-client library for this. The simple approach was to do the g+ access in pure js on the client and then lookup and push the results to my appengine app. It isnt as secure as doing via the backend, but it is only for displayname and icon (which can be set manually anyway).
I did need to make some other tweaks to make it work though...
following this workflow:
https://developers.google.com/+/web/signin/javascript-flow
Important things to note:
step1 should also state that you MUST fill out "APIs & auth" -> "Consent screen" field "PRODUCT NAME" and "EMAIL ADDRESS" or you get weird errors
You (might) have to do this before you generate the credential (or delete and recreate it)
(credit to answer: Error: invalid_client no application name)
set meta google-signin-scope to "profile" (or maybe "email")
remove the meta header for google-signin-requestvisibleactions (otherwise i got a frame sameorigin error)
obviously the button line from step4 needs to go after the body tag in your document
skip step2, the code from step2 is also included in step4
also on the workflow page, the 'working example' button on that page does not work (dont try it)
Once i did that I could put the following in the successful callback code and do a lookup:
gapi.client.load('plus','v1', function(){
var request = gapi.client.plus.people.get({ 'userId': 'me' });
request.execute(function(resp) {
console.log('Retrieved profile for:' + resp.displayName);
console.log(resp);
console.log(resp.result);
console.log(resp.result.displayName);
console.log(resp.result.image);
});
});
you can see here full example on how to use client library
https://code.google.com/p/google-api-python-client/source/browse/samples/plus/plus.py
i see a snippet of the code stating
try:
person = service.people().get(userId='me').execute()
print 'Got your ID: %s' % person['displayName']
https://developers.google.com/+/api/latest/people#resource
so basically person['image']['url'] will be your path to user's avatar.
full folder: https://code.google.com/p/google-api-python-client/source/browse/samples/plus/
I am using django_bootstrap.py there are similar errors but i could not find solution to it. I am using django helper(please do not suggest non-rel)
What i was trying to do was, inside a static html js website attaching a feature of sending mail, through a contact form. The form would take the data, and jQuery would validate and make a POST AJAX request to the url "/sendmail/" the views.py i have the following code:
def sendmail(request):
logging.info("here1")
msg = request.POST['comment']; sub = request.POST['subject']
name = request.POST['name']; frm = request.POST['email']
sender = name + " " + frm
logging.info(sender)
a = mail.send_mail(sender=sender,
to="to#example.com",
subject=sub,
body=msg)
logging.info(request)
logging.info(a)
return http.HttpResponse("1")
I get absolutely no error when i remove the line:
a = mail.send_mail(sender=sender,
to="to#example.com",
subject=sub,
body=msg)
However with that line being there, i get the following error:
<class 'django.core.exceptions.ImproperlyConfigured'>: You haven't set the DATABASE_ENGINE setting yet.
I look at my settings.py file and try making some changes:
1 adding two lines as done in django-nonrel settings.py
DATABASES['native'] = DATABASES['default']
DATABASES['default'] = {'ENGINE': 'dbindexer', 'TARGET': 'native'}
This gave a 500 error on server and the page did not open.
2 I tried putting
DATABASE_ENGINE = 'dummy'
This works locally but doesnot work on server(appspot).
3 I tried putting
DATABASE_ENGINE = 'appengine'
This too gives a 500 error.
Please let me know how to solve it.
This looks messed up in all sorts of ways. Don't use bootstrap.py, it looks outdated as it's trying to load django 0.96. GAE now supports django 1.3.
Please don't use the django helper. It's not being maintained or supported by anyone. If you have problems with it, the solution is to upgrade to nonrel.
I recommend installing django-nonrel properly. Keep in mind django-nonrel is a full replacement of django. Most of it's the same, but some parts are modified to work with appengine backends. You cannot take pieces of django-nonrel and expect it to work with normal django, without a fair bit of hackery. The DATABASES lines in the settings file will only work with django-nonrel.
http://www.allbuttonspressed.com/projects/djangoappengine
Django helper doesn't have an email backend that uses appengine's email API. That's available in Django-nonrel's djangoappengine package.
If you are not using a database in your application, you can set DATABASES = {} in your settings.py file. This will fix the problem "You haven't set the DATABASE_ENGINE setting yet".
I am trying to put together a bash or python script to play with the facebook graph API. Using the API looks simple, but I'm having trouble setting up curl in my bash script to call authorize and access_token. Does anyone have a working example?
Update 2018-08-23
Since this still gets some views and upvotes I just want to mention that by now there seems to exist a maintained 3rd party SDK: https://github.com/mobolic/facebook-sdk
Better late than never, maybe others searching for that will find it. I got it working with Python 2.6 on a MacBook.
This requires you to have
the Python facebook module installed: https://github.com/pythonforfacebook/facebook-sdk,
an actual Facebook app set up
and the profile you want to post to must have granted proper permissions to allow all the different stuff like reading and writing.
You can read about the authentication stuff in the Facebook developer documentation. See https://developers.facebook.com/docs/authentication/ for details.
This blog post might also help with this: http://blog.theunical.com/facebook-integration/5-steps-to-publish-on-a-facebook-wall-using-php/
Here goes:
#!/usr/bin/python
# coding: utf-8
import facebook
import urllib
import urlparse
import subprocess
import warnings
# Hide deprecation warnings. The facebook module isn't that up-to-date (facebook.GraphAPIError).
warnings.filterwarnings('ignore', category=DeprecationWarning)
# Parameters of your app and the id of the profile you want to mess with.
FACEBOOK_APP_ID = 'XXXXXXXXXXXXXXX'
FACEBOOK_APP_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
FACEBOOK_PROFILE_ID = 'XXXXXX'
# Trying to get an access token. Very awkward.
oauth_args = dict(client_id = FACEBOOK_APP_ID,
client_secret = FACEBOOK_APP_SECRET,
grant_type = 'client_credentials')
oauth_curl_cmd = ['curl',
'https://graph.facebook.com/oauth/access_token?' + urllib.urlencode(oauth_args)]
oauth_response = subprocess.Popen(oauth_curl_cmd,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE).communicate()[0]
try:
oauth_access_token = urlparse.parse_qs(str(oauth_response))['access_token'][0]
except KeyError:
print('Unable to grab an access token!')
exit()
facebook_graph = facebook.GraphAPI(oauth_access_token)
# Try to post something on the wall.
try:
fb_response = facebook_graph.put_wall_post('Hello from Python', \
profile_id = FACEBOOK_PROFILE_ID)
print fb_response
except facebook.GraphAPIError as e:
print 'Something went wrong:', e.type, e.message
Error checking on getting the token might be better but you get the idea of what to do.
Here you go, as simple as it can get. Doesn’t require any 3rd-party SDK etc.
Make sure Python 'requests' module is installed
import requests
def get_fb_token(app_id, app_secret):
url = 'https://graph.facebook.com/oauth/access_token'
payload = {
'grant_type': 'client_credentials',
'client_id': app_id,
'client_secret': app_secret
}
response = requests.post(url, params=payload)
return response.json()['access_token']
Easy! Just use facebook-sdk.
import facebook
app_id = 'YOUR_APP_ID'
app_secret = 'YOUR_APP_SECRET'
graph = facebook.GraphAPI()
# exactly what you're after ;-)
access_token = graph.get_app_access_token(app_id, app_secret)
You first need to set up an application. The following will then spit out an access token given your application ID and secret:
> curl -F type=client_cred -F client_id=[...] -F client_secret=[...] https://graph.facebook.com/oauth/access_token
Since a web browser needs to be involved for the actual authorization, there is no such thing as a "standalone script" that does it all. If you're just playing with the API, or are writing a script to automate something yourself, and want a access_token for yourself that does not expire, you can grab one here: http://fbrell.com/auth/offline-access-token
There IS a way to do it, I've found it, but it's a lot of work and will require you to spoof a browser 100% (and you'll likely be breaking their terms of service)
Sorry I can't provide all the details, but the gist of it:
assuming you have a username/password for a facebook account, go curl for the oauth/authenticate... page. Extract any cookies returned in the "Set-Cookie" header and then follow any "Location" headers (compiling cookies along the way).
scrape the login form, preserving all fields, and submit it (setting the referer and content-type headers, and inserting your email/pass) same cookie collection from (1) required
same as (2) but now you're going to need to POST the approval form acquired after (2) was submitted, set the Referer header with thr URL where the form was acquired.
follow the redirects until it sends you back to your site, and get the "code" parameter out of that URL
Exchange the code for an access_token at the oauth endpoint
The main gotchas are cookie management and redirects. Basically, you MUST mimic a browser 100%. I think it's hackery but there is a way, it's just really hard!
s29 has the correct answer but leaves some steps to solve. The following script demonstrates a working script for acquiring an access token using the Facebook SDK:
__requires__ = ['facebook-sdk']
import os
import facebook
def get_app_access_token():
client = facebook.GraphAPI()
return client.get_app_access_token(
os.environ['FACEBOOK_APP_ID'],
os.environ['FACEBOOK_APP_SECRET'],
)
__name__ == '__main__' and print(get_app_access_token())
This script expects the FACEBOOK_APP_ID and FACEBOOK_APP_SECRET environment variables are set to the values for your app. Feel free to adapt that technique to load those values from a different source.
You must first install the Facebook SDK (pip install facebook-sdk; python get-token.py) or use another tool like rwt to invoke the script (rwt -- get-token.py).
Here is the Python Code. Try running some of these examples on command line, they work fine for me. See also — http://www.pythonforfacebook.com/