Parsing incoming mail with Google App Engine? - google-app-engine

We have our mail setup with Google Apps. We want to be able to run some regular expressions on incoming mail and process this information.
Is this possible today with Google App Engine? Does Google provide some kind of infrastructure that can do this?

from google documentation here:
Receiving Mail
Your app can receive email at addresses of the following form:
string#appid.appspotmail.com
Note that even if your app is deployed on a custom domain, your app can't receive email sent to addresses on that domain.
Email messages are sent to your app as HTTP requests. These requests are generated by App Engine and posted to your app. In your app's configuration, you specify handlers that will be called to handle these HTTP requests. In your handlers, you receive the MIME data for email messages, which you then parse into its individual fields.
Email messages are sent to your app as HTTP POST requests using the following URL:
/_ah/mail/address
where address is a full email address, including domain name.
The ability to receive mail in your app is disabled by default. To enable your app to receive mail, you must specify that you want this service enabled in your app.yaml file by including this:
inbound_services:
- mail
The Python SDK defines InboundMailHandler, a webapp class for handling incoming email. To use InboundMailHandler, you subclass it and override the receive() method. The receive() method is called with an argument of class InboundEmailMessage, another class defined by the Python SDK.
InboundMailHandler is in the google.appengine.ext.webapp.mail_handlers package. You can create an instance of InboundEmailMessage like this:
import logging, email
from google.appengine.ext import webapp
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler
from google.appengine.ext.webapp.util import run_wsgi_app
class LogSenderHandler(InboundMailHandler):
def receive(self, mail_message):
logging.info("Received a message from: " + mail_message.sender)
The InboundEmailMessage object includes attributes to access other message fields:
subject contains the message subject.
sender is the sender's email address.
to is a list of the message's primary recipients.
cc contains a list of the cc recipients.
date returns the message date.
attachments is a list of file attachments, possibly empty. Each value in the list is a tuple of two elements: the filename and the file contents.
original is the complete message, including data not exposed by the other fields such as email headers, as a Python email.message.Message.

handle_incoming_email.py
app.yaml

Update: It's now supported.
Processing incoming email is not yet supported. It is however on their roadmap: http://code.google.com/appengine/docs/roadmap.html

Google don't currently support handling email in App Engine, though it is on the roadmap. In the meantime, services like smtp2web will handle it for you (disclaimer: I wrote smtp2web).

You could setup an email account and have an external server (one you create and host outside of AE) access the gmail account via IMAP. Your "mail server" then reads the messages and accesses the /email API of your app on AE.
Python has an email module, so you could post the entire message there, or if that doesn't work (due to whatever restrictions), you could preprocess it on your mail server and post the simplified version to your app.
The downside is that you'll have to resort to polling for information, but that should be ok since email is accepted to have somewhat of a delay.

As another option to the answer from Gabriel I would recommend to use go environment of App Engine on Sending and Receiving Mail with the Mail API.
From The Documentation:
Receiving Mail
Your app can receive email at addresses of the following form:
anything#appid.appspotmail.com
Compare to a configuration on handling incoming mail in python as discussed here, enabling incoming mail in your app's app.yaml file is fairly simple:
inbound_services:
- mail
Name your app file as mail.go, then register a handler to the /_ah/mail/ path and read the email's data from the *http.Requestlike using net/mail like this:
func incomingMail(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
defer r.Body.Close()
var b bytes.Buffer
if _, err := b.ReadFrom(r.Body); err != nil {
log.Errorf(ctx, "Error reading body: %v", err)
return
}
log.Infof(ctx, "Received mail: %v", b)
}
Sending Mail
Follow this guideline to register your sender emails as authorized senders
Use the mail.Message type to set the sender, recipient, subject, and body of the message.
Send the email with the mail.Send function.
func confirm(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
addr := r.FormValue("email")
url := createConfirmationURL(r)
msg := &mail.Message{
Sender: "Example.com Support <support#example.com>",
To: []string{addr},
Subject: "Confirm your registration",
Body: fmt.Sprintf(confirmMessage, url),
}
if err := mail.Send(ctx, msg); err != nil {
log.Errorf(ctx, "Couldn't send email: %v", err)
}
}
Deploy
The complete sample code of both Receiving and Sending is available here on GitHub:
GoogleCloudPlatform/golang-samples/docs/appengine/mail/mail.go
To clone the sample code, go to your Console. Click the button to open Cloud Shell:
then similar with this quickstart enter the steps below:
$ SOURCEDIR=https://github.com/GoogleCloudPlatform/golang-samples.git
$ TUTORIALDIR=~/src/your-application-id/go_gae_samples
$ git clone $SOURCEDIR $TUTORIALDIR
$ cd $TUTORIALDIR
$ git checkout master
$ cat docs/appengine/mail/app.yaml
$ cat docs/appengine/mail/mail.go
$ goapp serve docs/appengine/mail/app.yaml
From here you can access the app on port 8080 by using Web preview.
To terminate press Ctrl+C in the Cloud Shell.
Finally you may deploy your app
goapp deploy -application your-application-id -version 0
Click the URL to visit it
http://your-application-id.appspot.com/
Then send an email to anything#your-application-id.appspotmail.com see if it works.

Related

Using Cloud Firestore with AppEngine Go Standard Environment returns rpc error when running on AppEngline

I'm trying to use Firestore in my AppEngine (standard environment) app written in Go. I've been following the "Getting Started with Cloud Firestore" guide and have been using the firestore package documentation to implement a simple example that works fine when running it on my local dev server.
However when I deploy the app and try the deployed version the call to DocumentRef.Set() fails with the error
rpc error: code = Unavailable desc = all SubConns are in TransientFailure
This is my code that reproduces the issue:
func init() {
http.HandleFunc("/test", testHandler)
}
type testData struct {
TestData string `firestore:"myKey,omitempty"`
}
func testHandler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
var firestoreClient *firestore.Client
var firebaseApp *firebase.App
var err error
conf := &firebase.Config{ProjectID: "my-project"}
firebaseApp, err = firebase.NewApp(ctx, conf)
if err != nil {
fmt.Fprintf(w, "Failed to create a new firestore app: %v", err)
return
}
firestoreClient, err = firebaseApp.Firestore(ctx)
if err != nil {
fmt.Fprintf(w, "Failed to create a new firestore client: %v", err)
return
}
data := testData{"my value"}
_, err = firestoreClient.Collection("testCollection").Doc("testDoc").Set(ctx, data)
if err != nil {
fmt.Fprintf(w, "Failed to create a firestore document: %v", err)
return
}
firestoreClient.Close()
fmt.Fprint(w, "Data stored in Firestore successfully")
}
As mentioned before, on the dev server this works fine. So there the returned page contains the text Data stored in Firestore successfully.
When running the deployed code I get Failed to create a firestore document: rpc error: code = Unavailable desc = all SubConns are in TransientFailure instead. Why do I get this error and how can I avoid it?
I've raised an issue about this in the Firestore client library issue tracker and it seems like the situation is a bit complex.
When using App Engine the Firestore client library's network connections goes trough the App Engine socket library. However sockets is only available for paid App Engine apps:
Sockets are only available for paid apps, and traffic from sockets is billed as outgoing bandwidth. Sockets are also limited by daily and per minute (burst) quotas.
So this is the reason why the Firestore client library fails. For small scale projects it's possible to enable billing of your App Engine app and still stay within the free range. If billing is enabled it should work when the app is deployed as well.
However if you are living within the European Union you are not allowed to have a paid App Engine app for non commercial purposes due to Google policies:
If you are located in the European Union and the sole purpose for which you want to use Google Cloud Platform services has no potential economic benefit you should not use the service. If you have already started using Google Cloud Platform, you should discontinue using the service. See Create, modify, or close your billing account to learn how to disable billing on your projects.
So if you are in Europe or for some other reason are unable to use have a paid App Engine app you will not be able to use the Firestore client library.
One alternative in this case is to use the Firestore REST API instead and manually make HTTP requests to Firestore. It's a bit more work, but for smaller scale projects it works.
On AppEngine you need to create a client that uses Http client provided by urlfetch service.
The firestore.NewClient() function accepts ClientOptions parameters that you can create using WithHTTPCLient() function.
Here is an article on issuing HTTP requests from AppEngine Go.
That should help.

smtp sendmail in Dockerised Golang Web App in GAE doesn't work

I have a dockerised web app deployed on GAE wriiten in Go. The payment module uses stripe checkout API and on success triggers an email notification.
On debugging, I observe that the following line of code is not executed. I have tried port 587 and the result is the same.
err := smtp.SendMail("smtp.gmail.com:465", auth, from, []string{to}, []byte(msg))
I have the same app on my local m/c and this feature works on it. Am not using docker on my local m/c though.
I am using the same user credentials as my GAE account in the 'from' user fields. Could that be the reason that the code fails. Or should the smtp service auth parameters along with the port to be exposed be described in the dockerfile. What would be the correct way to map port 465 or 587 in GAE given that only 4 ports are available?
I am using Golang image 1.7.1
docker logs doesn't show any errors. But the email doesn't get sent.
etc/resolv.conf of the container has the following DNS entries
search c.cloud-devshell-prod.internal. google.internal.
nameserver 169.254.169.254
options: ndots5
Would appreciate any suggestions..
Thanks
Followed instructions on the link
https://cloud.google.com/appengine/docs/flexible/go/sending-emails-with-mailgun
Set up and account with mailgun and got it to work. Mails get sent after running docker.

Go, Appengine, SMTP, Gmail

For some reason I cannot figure out how to send emails using a gmail account, Appengine and Golang.
Here's what I've done:
I went to Google Cloud Platform > Appengine > Settings > Select Project and I added the gmail account on Email API authorized senders.
I' tried to make this work using the code from (https://golang.org/pkg/net/smtp/#pkg-examples) (func SendMail)
package main
import (
"log"
"net/smtp"
)
func main() {
// Set up authentication information.
auth := smtp.PlainAuth("", "user#gmail.com", "password", "smtp.gmail.com")
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
to := []string{"recipient#example.net"}
msg := []byte("To: recipient#example.net\r\n" +
"Subject: discount Gophers!\r\n" +
"\r\n" +
"This is the email body.\r\n")
err := smtp.SendMail(smtp.gmail.com:587", auth, "sender#example.org", to, msg)
if err != nil {
log.Fatal(err)
}
}
On the front-end (JavaScript) I get an unsuccessful response after trying to run this code.
I've been running this on the appengine staging server
I tried different smtp server, ports, users and it still not work (support.google.com/a/answer/176600?hl=en)
I found a few examples on github and some other blog and I tried them but it didn't make different.
github.com/golang/go/wiki/SendingMail
nathanleclaire.com/blog/2013/12/17/sending-email-from-gmail-using-golang/
On all the examples it everything looks straight forward but there's something that I'm definitely missing or misunderstanding.
There're some limitations with establishing raw tcp connections on GAE:
https://cloud.google.com/appengine/docs/go/sockets/#limitations_and_restrictions
I would recommend to use GAE mail api (which is slightly diffrent from standart smtp package) to send emails:
https://cloud.google.com/appengine/docs/go/mail/sending-receiving-with-mail-api

Google Pub/Sub access rights

I created a topic in my project Project 1 and I have an app on Google app engine which posts every minute a message to this topic.
I have a google cloud compute machine in a second project (Project 2) which subscribed to this topic and receives the messages.
I did not give any access right to the machine on my Project 2, but even without access rights, It managed to receive the messages. More precisely, I did not write specific permissions associated to the topic I created.
My questions are:
1- is this normal? Shouldn't the machine on Project 2 get a "forbidden access error"?
2- how can I restrain access on a certain topic?
Here is the code of my subscription part:
import httplib2
import base64
import pandas
import json
from apiclient import discovery
from oauth2client import client as oauth2client
from oauth2client.client import SignedJwtAssertionCredentials
from oauth2client.client import GoogleCredentials
def create_pubsub_client(http=None):
credentials = GoogleCredentials.get_application_default()
if not http:
http = httplib2.Http()
credentials.authorize(http)
return discovery.build('pubsub', 'v1', http=http)
client = create_pubsub_client()
# You can fetch multiple messages with a single API call.
batch_size = 1
subscription_str = 'projects/<myproject1>/subscriptions/testo'
# Create a POST body for the Pub/Sub request
body = {
# Setting ReturnImmediately to false instructs the API to wait
# to collect the message up to the size of MaxEvents, or until
# the timeout.
'returnImmediately': False,
'maxMessages': batch_size,
}
while True:
resp = client.projects().subscriptions().pull(
subscription=subscription_str, body=body).execute()
received_messages = resp.get('receivedMessages')
if received_messages is not None:
ack_ids = []
for received_message in received_messages:
pubsub_message = received_message.get('message')
if pubsub_message:
# Process messages
msg = base64.b64decode(str(pubsub_message.get('data')))
treatment(msg)
# Get the message's ack ID
ack_ids.append(received_message.get('ackId'))
# Create a POST body for the acknowledge request
ack_body = {'ackIds': ack_ids}
# Acknowledge the message.
client.projects().subscriptions().acknowledge(
subscription=subscription_str, body=ack_body).execute()
The ability of the machine in Project 2 to access the topic/subscription in Project 1 depends entirely on how machine is authenticated. If it is authenticated with something that has permissions on both projects, e.g., your developer account, then you would be able to access the subscription on the topic in Project 1. That is normal.
If you want to restrict the access, create a service account in Project 1 and set the permissions on your topic and/or subscription to allow only that service account. You would do so in the Pub/Sub section of the Google Developers Console. Then, only machines authenticated via that service account will be able to access them.

Sending Mail from Google App Engine

I am trying to send an email from google app engine using the python 2.7 library but I keep getting Unauthorized sender in the logs. I have tried my gmail account I created the application with as the sender, I registered another gmail address as a developer and tried that but still get Unauthorized sender. I am not sure if it matters but I do have a domain name registered to this application.
Here is the code I am trying:
message = mail.EmailMessage()
message.sender = "ron.....#gmail.com"
message.subject = "Inquiry"
message.to = "ron.....#gmail.com"
message.body = "Please work"
message.send()
I have looked at other articles to no avail.
Google Appengine sending emails: [Error] unauthorized sender
InvalidSenderError: Unauthorized sender (Google App Engine)
from google.appengine.api import mail
mail.send_mail(sender="stackoverflow.com Hossam <Hossam#stackoverflow.com>",
to="rsnyder <rsnyder#stackoverflow.com>",
subject="How to send an e-mail using google app engine",
body="""
Dear rsnyder:
This example shows how to send an e-mail using google app engine
Please let me know if this is what you want.
Best regards,
""")
EDIT:
Note that sender must be an administrator of the application, so in case that you are not and administrator, follow these steps from the post google app engine: how to add adminstrator account
I found the issue. It was the wrong version of the code. I switched to a version 2 and didn't realize I had to activate it.

Resources