App Engine - Check if incoming email is from Google group member - python

I'm trying to restrict incoming emails to my app so it only accepts mail from members of a google group. More specifically, I want to only add the contents of the email to my datastore if they are part of the group. I've found the hasMember/IsMember method here: https://developers.google.com/admin-sdk/directory/v1/reference/members/hasMember and think this may be what I am looking for, but I do not know how to use it as they haven't provided an example and I'm very new to this.
Would this be the correct API to use for this? Here is my incoming mail handler code, I have added the IF statement comment to show what I would like to do:
import webapp2
import logging
from google.appengine.ext.webapp import mail_handlers
from google.appengine.api import mail
import os
from main import WorkRequest
import re
class IncomingMailHandler(mail_handlers.InboundMailHandler):
def receive(self, message):
(encoding, payload) = list(message.bodies(content_type='text/plain'))[0]
body_text = payload.decode()
logging.info('Received email message from %s, subject "%s": %s' %
(message.sender, message.subject, body_text))
logging.info (message.sender)
logging.info(message.subject)
logging.info(body_text)
#IF MESSAGE_SENDER == MEMBER OF GOOGLE GROUP:
wr = WorkRequest()
wr.email = message.sender
wr.userId = None
wr.title = message.subject
wr.content = body_text
wr.status = "OPEN"
wr.submission_type = "EMAIL"
wr.assigned_to = "UNASSIGNED"
wr.put()
application = webapp2.WSGIApplication([('/_ah/mail/.+', IncomingMailHandler)],debug=True)

Related

Microsoft Teams Python Botbuilder Proactive Messaging

What was simple in Webex now seems fairly complicated in the Microsoft world.
What I specifically am looking to do is:
Create a bot in the Azure Bot Framework (Done)
Identify recipient ids using the botbuilder sdk using the recipient email
Use Botframework-Connector to individually identify these recipients, create new conversations, and proactively message them
This is what I have been using so far
https://pypi.org/project/botframework-connector/
from botbuilder.schema import *
from botframework.connector import ConnectorClient
from botframework.connector.auth import MicrosoftAppCredentials
APP_ID = 'azure_bot_app_id'
APP_PASSWORD = 'azure_bot_app_password'
SERVICE_URL = 'azure_bot_messaging_endpoint'
CHANNEL_ID = 'msteams'
BOT_ID = 'azure_bot_subscription_id'
RECIPIENT_ID = 'msteams_individual_user_id'
credentials = MicrosoftAppCredentials(APP_ID, APP_PASSWORD)
connector = ConnectorClient(credentials, base_url=SERVICE_URL)
conversation = connector.conversations.create_conversation(ConversationParameters(
bot=ChannelAccount(id=BOT_ID),
members=[ChannelAccount(id=RECIPIENT_ID)]))
connector.conversations.send_to_conversation(conversation.id, Activity(
type=ActivityTypes.message,
channel_id=CHANNEL_ID,
recipient=ChannelAccount(id=RECIPIENT_ID),
from_property=ChannelAccount(id=BOT_ID),
text='Hello Person!'))
Is this even close to the right approach?
This was the easiest way I found to make it work.
from config import DefaultConfig
from botframework.connector.connector_client import ConnectorClient
from botframework.connector.models import ConversationParameters
from botframework.connector.auth.microsoft_app_credentials import MicrosoftAppCredentials
from botbuilder.core import MessageFactory
from botbuilder.schema import ChannelAccount
CONFIG = DefaultConfig()
recipient_id = <<RECIPIENT_ID>>
to = ChannelAccount(id=recipient_id)
bot_channel = ChannelAccount(id='msteams')
MicrosoftAppCredentials.trust_service_url(CONFIG.SERVICE_URL)
credentials = MicrosoftAppCredentials(CONFIG.APP_ID, CONFIG.APP_PASSWORD)
conn_client = ConnectorClient(credentials, CONFIG.SERVICE_URL)
message_activity = MessageFactory.text(f"Personal message from the Bot!");
conversation_params = ConversationParameters(members=[to], channel_data={ 'tenant': { 'id': CONFIG.TENANT_ID } })
conversation = conn_client.conversations.create_conversation(conversation_params)
conn_client.conversations.send_to_conversation(conversation.id, message_activity)
It is easy to infer all the uppercase variables.
The <<RECIPIENT_ID>> is the MS Teams ID of the user you want to send the message.
Hope this helps.
MSFT does not provide good examples in Python.
With a cursory glance it looks ok (I don't work in Python so can't actually run the example). One thing that does look missing in the TrustServiceUrl call. See here for details.

App Engine Datastore storing email in wrong format

My app receives incoming email and saves the sender's email address into the datastore. Problem is it saves them in this format:
John Smith <jsmith#email.com>
Because of the way my app and it's queries are set up I can only search for addresses in this format: jsmith#email.com
I have tried to use regex to format the messages but it doesn't work for some reason, I get list index out of range errors on every expression I try. here is the code for my mail handler if that is helpful.
I have checked the logs in App Engine and incoming messages do come in in the format I need, but then I check the datastore entities and it adds it in with the name as well.
I just need to know how I can get email addresses stored without the extra bits.
import webapp2
import logging
from google.appengine.ext.webapp import mail_handlers
from google.appengine.api import mail
import os
from main import WorkRequest
import re
class IncomingMailHandler(mail_handlers.InboundMailHandler):
def receive(self, message):
(encoding, payload) = list(message.bodies(content_type='text/plain'))[0]
body_text = payload.decode()
logging.info('Received email message from %s, subject "%s": %s' %
(message.sender, message.subject, body_text))
logging.info (message.sender)
logging.info(message.subject)
logging.info(body_text)
sender = str(message.sender)
logging.info(sender)
email_address = re.findall('<([^>])>', sender)[0]
wr = WorkRequest()
wr.email = email_address
wr.userId = None
wr.title = message.subject
wr.content = body_text
wr.status = "OPEN"
wr.submission_type = "EMAIL"
wr.assigned_to = "UNASSIGNED"
wr.put()
application = webapp2.WSGIApplication([('/_ah/mail/.+', IncomingMailHandler)],debug=True)
Unless something got mangled when your code fragement was posted, that regex is very unlikely to match. Try
email_address = re.findall('<(.*?)>', sender)[0]
That will handle that one particular form of address.
Alternatively, instead of regex:
email = email.split('<')[1].split('>')[0]
Use the parseaddr function from the standard library's email package.
>>> from email.utils import parseaddr
>>> sender = 'John Smith <jsmith#email.com>'
>>> name, address = parseaddr(sender)
>>> print name
John Smith
>>> print address
jsmith#email.com
From the docs:
Parse address – which should be the value of some address-containing
field such as To or Cc – into its constituent realname and email
address parts. Returns a tuple of that information, unless the parse
fails, in which case a 2-tuple of ('', '') is returned.

Send transactional and marketing emails using 'SendInBlue'

I want to send transactional and marketing emails using 'SendInBlue'. I also want to use Python language to do the same. I have visited the API doc of SendInBlue and followed the same procedure, still unsuccessful in sending the emails.
from mailin import Mailin
m = Mailin("https://api.sendinblue.com/v2.0","ScrWGqd296ya0CWq")
data = { "to" : {"aman#gmail.com":"to whom!"},
"from" : ["amandeep#gmail.com", "from email!"],
"subject" : "Subject...",
"html" : "This is the <h1>HTML</h1>",
"attachment" : ["https://example.com/path-to-file/filename1.pdf", "https://example.com/path-to-file/filename2.jpg"]
}
result = m.send_email(data)
print(result)
I have also downloaded mailin-api-python from github and ran this script. I don't have any idea where to setup to my smtp details.
**I have changed the API key just for security purpose.
I would strongly recommend you to use the latest version of SendinBlue's Python wrapper where they have provided an example
from __future__ import print_function
import time
import sib_api_v3_sdk
from sib_api_v3_sdk.rest import ApiException
from pprint import pprint
# Configure API key authorization: api-key
configuration = sib_api_v3_sdk.Configuration()
configuration.api_key['api-key'] = 'API-KEY'
# create an instance of the API class
api_instance = sib_api_v3_sdk.SMTPApi(sib_api_v3_sdk.ApiClient(configuration))
senderSmtp = sib_api_v3_sdk.SendSmtpEmailSender(name="test",email="youremail#gmail.com")
sendTo = sib_api_v3_sdk.SendSmtpEmailTo(email="recipientEmail#gmail.com",name="Recipient Name")
arrTo = [sendTo] #Adding `to` in a list
send_smtp_email = sib_api_v3_sdk.SendSmtpEmail(sender=senderSmtp,to=arrTo,html_content="This is a test",subject="This is a test subject") # SendSmtpEmail | Values to send a transactional email
try:
# Send a transactional email
api_response = api_instance.send_transac_email(send_smtp_email)
pprint(api_response)
except ApiException as e:
print("Exception when calling SMTPApi->send_transac_email: %s\n" % e)
I got a sample script working:
I successfully received the email and the messageId as the response.
Please let me know if it helps!

Run particular Django script in background

I am developing a Gmail extracting app and using Gmail API to fetch mail from server. the problem lies in the fact that fetch time for mails is too large even though I used threading in back end framework. now I am going to implement one feature which will suggest user opting for bulk download that "once your download is ready, we will mail you" but for that i want to run download.py mentioned below in app tree in background and once the fetch is over it will get terminated.
And in the very bottom of the code i want to mail user that their download is ready but its not working though i have defined the mail server in settings.py .
download.py
import httplib2, base64
from stripogram import html2text
from oauth2client.django_orm import Storage
from apiclient.discovery import build
from oauth2client import client
from django.contrib.auth.models import User
from .models import CredentialsModel
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
from gextracto import models
from gextracto.models import UserData
from django.core.mail import EmailMessage
from django.core import mail
connection = mail.get_connection()
class ListMails(APIView):
"""
Gets a list of a specified number mail ids for a particular label
Extracts the email in the form of plain/text
The API returns all the extracted mails
"""
authentication_classes = (authentication.SessionAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def extract_headers(self, message):
"""
Extract the headers for a single mail and returns it
{To, From, Subject}
"""
needed_fields = ('From', 'To', 'Subject')
return {i['name']:i['value'] for i in message['payload']['headers'] if i['name'] in needed_fields}
def get_message_body(self, message):
"""
Get the body of an email
Recursively look for the body for different mimetypes
Returns the body as text/plain
"""
if 'payload' in message:
return self.get_message_body(message['payload'])
elif 'parts' in message:
return self.get_message_body(message['parts'][0])
else:
data = base64.urlsafe_b64decode(message['body']['data'].encode('ASCII'))
markdown_data = html2text(data)#.decode('utf-8', "replace")
data = data.replace("\n", "<br/>")
# return {markdown, html}
return {'markdown':unicode( markdown_data,"ISO-8859-1"), 'html':unicode(data,"ISO-8859-1")} if markdown_data else {'html':unicode(data,"ISO-8859-1")}
def message_content_html(self, userId, message_id, service):
"""
Make queries to get the content for a mail given its message id
Returns all the content
"""
content = {'id':message_id}
# try
message = service.users().messages().get(userId=userId, id=message_id).execute()
mimetype = message['payload']['mimeType']
if mimetype == 'text/html':
return {}
#
else:
body = self.get_message_body(message)
if body == "":
body = "<empty message>"
headers = self.extract_headers(message)
content['body'] = body
content.update(headers)
return content
def collect_mails(self, user, messages, service):
"""
Collect the content for all the mails currently downloaded
"""
all_messages = []
try:
for message in messages:
content = self.message_content_html(user.username, message['id'], service)
if content:
all_messages.append(content)
return all_messages
# return empty list if no messages were downloaded
except KeyError:
return []
def get(self, request, format=None):
"""
Handles the GET request to get all the mails for a label
Paginages through the GAPI content if required
API returns all the messages
{To, From, Subject, body}
"""
user = request.user
storage = Storage(CredentialsModel, 'id', user, 'credential')
credentials = storage.get()
http_auth = credentials.authorize(httplib2.Http())
service = build('gmail', 'v1', http=http_auth)
user_Id = user.username
label_id = request.GET['label']
# try
# call Google API with a request to get a list of all the labels
response = service.users().messages().list(userId=user_Id, labelIds=label_id, maxResults=100).execute()
all_messages = self.collect_mails(user, response['messages'], service)
if not all_messages:
return Response([])
else:
if 'nextPageToken' in response:
page_token_flag = True
# request more more mails if the download limit has not yet been satisfied
while(page_token_flag):
response = service.users().messages().list(userId=user_Id, pageToken=response['nextPageToken'], maxResults=100).execute()
all_messages.append(self.collect_mails(user, response['messages'], service))
print(all_messages)
#for x in range(0,len(all_messages)):
#b=all_messages[10]
#instance= UserData(user_id=user ,label=label_id, sender = b['From'] , subject=b['Subject'] , body=b['body'])
#instance.save()
page_token_flag = 'nextPageToken' in response
##
for x in range(0,len(all_messages)):
b=all_messages[10]
instance= UserData(user_id=user ,label=label_id, sender = b['From'] , subject=b['Subject'] , body=b['body'])
instance.save()
print ("Hi i am here!!!")
email = EmailMessage('Your Download Ready!', 'http://127.0.0.1:8000/admin/gextracto/userdata/', to=[user], connection=connection)
email.send()
connection.close()
return Response(all_messages)
Please tell me the way to run it in background. if need any other info please do ask. Thanks
Don't know the exact requirements but I'll think about Celery to run background tasks. This approach allows to manage all post-script activities in native Django manner.
Also you can think about running the Django script using cron (as manage.py command) - but it can lead to some limitations.
What about sending emails failure - believe, you don't need to close connection after sending email. Usually I use send_mail()/send_mass_mail() functions - please, check their code to get an idea.

google app engine, python , unicode, email, mail api

I'm using an open source web service python application to send email through GAE but if the name or email body contains Arabic or Hebrew characters the application throws some errors (e.g "The indicated parameters are not valid"). Therefore I need to know how to fix this issue. I have to note that I'm a Python beginner (one week since I started playing with Python).
#
import cgi
import os
import logging
import contextlib
from xml.dom import minidom
from xml.dom.minidom import Document
import exceptions
import warnings
import imghdr
from google.appengine.api import images
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from google.appengine.api import mail
import wsgiref.handlers
# START Constants
CONTENT_TYPE_HEADER = "Content-Type"
CONTENT_TYPE_TEXT = "text/plain"
XML_CONTENT_TYPE = "application/xml"
XML_ENCODING = "utf-8"
"""
Allows you to specify IP addresses and associated "api_key"s to prevent others from using your app.
Storage and Manipulation methods will check for this "api_key" in the POST/GET params.
Retrieval methods don't use it (however you could enable them to use it, but maybe rewrite so you have a "read" key and a "write" key to prevent others from manipulating your data).
Set "AUTH = False" to disable (allowing anyone use your app and CRUD your data).
To generate a hash/api_key visit https://www.grc.com/passwords.htm
To find your ip visit http://www.whatsmyip.org/
"""
AUTH = False
# END Constants
# START Exception Handling
class Error(StandardError):
pass
class Forbidden(Error):
pass
logging.getLogger().setLevel(logging.DEBUG)
#contextlib.contextmanager
def mailExcpHandler(ctx):
try:
yield {}
except (ValueError), exc:
xml_error_response(ctx, 400 ,'app.invalid_parameters', 'The indicated parameters are not valid: ' + exc.message)
except (Forbidden), exc:
xml_error_response(ctx, 403 ,'app.forbidden', 'You don\'t have permission to perform this action: ' + exc.message)
except (Exception), exc:
xml_error_response(ctx, 500 ,'system.other', 'An unexpected error in the web service has happened: ' + exc.message)
def xml_error_response(ctx, status, error_id, error_msg):
ctx.error(status)
doc = Document()
errorcard = doc.createElement("error")
errorcard.setAttribute("id", error_id)
doc.appendChild(errorcard)
ptext = doc.createTextNode(error_msg)
errorcard.appendChild(ptext)
ctx.response.headers[CONTENT_TYPE_HEADER] = XML_CONTENT_TYPE
ctx.response.out.write(doc.toxml(XML_ENCODING))
# END Exception Handling
# START Helper Methods
def isAuth(ip = None, key = None):
if AUTH == False:
return True
elif AUTH.has_key(ip) and key == AUTH[ip]:
return True
else:
return False
# END Helper Methods
# START Request Handlers
class Send(webapp.RequestHandler):
def post(self):
"""
Sends an email based on POST params. It will queue if resources are unavailable at the time.
Returns "Success"
POST Args:
to: the receipent address
from: the sender address (must be a registered GAE email)
subject: email subject
body: email body content
"""
with mailExcpHandler(self):
# check authorised
if isAuth(self.request.remote_addr,self.request.POST.get('api_key')) == False:
raise Forbidden("Invalid Credentials")
# read data from request
mail_to = str(self.request.POST.get('to'))
mail_from = str(self.request.POST.get('from'))
mail_subject = str(self.request.POST.get('subject'))
mail_plain = str(self.request.POST.get('plain'))
mail_html = str(self.request.POST.get('html'))
message = mail.EmailMessage()
message.sender = mail_from
message.to = mail_to
message.subject = mail_subject
message.body = mail_plain
if mail_html != None and mail_html != "":
message.html = mail_html
message.send()
self.response.headers[CONTENT_TYPE_HEADER] = CONTENT_TYPE_TEXT
self.response.out.write("Success")
# END Request Handlers
# START Application
application = webapp.WSGIApplication([
('/send', Send)
],debug=True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()
# END Application
mail_to = str(self.request.POST.get('to'))
mail_from = str(self.request.POST.get('from'))
mail_subject = str(self.request.POST.get('subject'))
mail_plain = str(self.request.POST.get('plain'))
mail_html = str(self.request.POST.get('html'))
I doubt you need to convert them to strings. Try without str(), it could work.

Categories