QueueTrigger Bindings for Sendgrid -Python - python-3.x

Guided by this post I have written the following queuetrigger code intended to send emails when a message is queued.
import logging
import sendgrid
import azure.functions as func
import os
def main(msg: func.QueueMessage) -> None:
logging.info('Python queue trigger function processed a queue item: %s',
msg.get_body().decode('utf-8'))
data = {
"personalizations": [
{
"to": [
{
"email": "rrrrrrrr"
}
],
"subject": "Sending with SendGrid is Fun"
}
],
"from": {
"email": "ghyu"
},
"content": [
{
"type": "text/plain",
"value": "and easy to do anywhere, even with Python"
}
]
}
print('Sending email using SendGrid:', data)
with open(os.environ[_AZURE_FUNCTION_SENDGRID_OUTPUT_ENV_NAME], 'wb') as f:
json.dump(data,f)
function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "msg",
"type": "queueTrigger",
"direction": "in",
"queueName": "outqueue1",
"connection": "storageaccountautom92bb_STORAGE"
},
{
"name": "outputMessage",
"type": "sendGrid",
"from": "ghyu",
"apiKey": "MY_SENDGRID_API_KEY",
"direction": "out"
}
],
"disabled": false
}
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "hjk",
"FUNCTIONS_WORKER_RUNTIME": "python",
"storageaccountautom92bb_STORAGE": "hjk",
"MY_SENDGRID_API_KEY": "tyhuE",
"_AZURE_FUNCTION_SENDGRID_OUTPUT_ENV_NAME" : "GIS klop",
"_AZURE_FUNCTION_QUEUE_INPUT_ENV_NAME" : "msg"
}
}
Whereas the function responds to messages as they queue, it is not able to send emails. It throws an error;
the following parameters are declared in function.json but not in Python: {'outputMessage'}
How best can I resolve this?
Are the outward bindings correct?

Azure Function banned the port of send email, so we must use sendgrid to send email.(This is a third part tools but it was been integrated into azure functions binding, so we can directly use it.)
For example, if you want to send email from email A to email B.
First, go to the sendgrid website, create a sender and verify the email A:
After that, email A is ready to send emails by sendgrid.
Now we need to generate a SendGrid API key and copy and store the API key:(This will be filled in the Values section of local.settings.json as an environment variable to read.)
Then, you can use it to send emails:
host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 3.1.0)"
}
}
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=0730bowmanwindow;AccountKey=xxxxxx;EndpointSuffix=core.windows.net",
"FUNCTIONS_WORKER_RUNTIME": "python",
"SendGrid_API_Key": "SG._-yYnhzER2SEbAvzOxSHnA.xxxxxx",
"0730bowmanwindow_STORAGE": "DefaultEndpointsProtocol=https;AccountName=0730bowmanwindow;AccountKey=xxxxxx;EndpointSuffix=core.windows.net"
}
}
function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "msg",
"type": "queueTrigger",
"direction": "in",
"queueName": "myqueue",
"connection": "0730bowmanwindow_STORAGE"
},
{
"type": "sendGrid",
"name": "sendGridMessage",
"direction": "out",
"apiKey": "SendGrid_API_Key",
"from": "emailA#emailA.com"
}
]
}
__init__.py
import logging
import json
import azure.functions as func
def main(msg: func.QueueMessage, sendGridMessage: func.Out[str]) -> None:
logging.info('Python queue trigger function processed a queue item: %s',
msg.get_body().decode('utf-8'))
value = "Sent from Azure Functions"
message = {
"personalizations": [ {
"to": [{
"email": "emailB#emailB.com"
}]}],
"subject": "Azure Functions email with SendGrid",
"content": [{
"type": "text/plain",
"value": value }]
}
sendGridMessage.set(json.dumps(message))
After that, I send a message to 'myqueue', and emailB get the email:
By the way, this can only guarantee successful delivery, because some mailboxes refuse to accept mail sent through sendgrid. In this case, you will still get a 200 response, but the recipient will not receive the mail.(In this case, the recipient needs to go to the mailbox settings to lift the relevant restrictions.)

Related

Where i can see my console logs on localhost and when the function is deployed?

i am using azure functions written in nodejs.
I have this azure function
module.exports = async function (context, req) {
const title = req.body.title;
console.log('title', title);
if (title) {
req.body.completed = false;
context.bindings.outputDocument = req.body;
context.res = {
body: { success: true, message: `Todo added successfully` }
};
} else {
context.res = {
status: 400,
body: { success: false, message: `Please add title field` }
};
}
};
and the binding
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
},
{
"type": "cosmosDB",
"name": "outputDocument",
"databaseName": "xxx",
"collectionName": "items",
"createIfNotExists": false,
"connectionStringSetting": "xxx",
"partitionKey": "/all",
"direction": "out"
}
],
"disabled": false
}
locally when i run
func host start
i don't see my console log statement.
How can i see on localhost ?
And where i need to go in my azure portal to see the logs there after deployment.
I tried to go in Function App - open my function and there the azure function but i can't see any logs there...
How can i see on localhost ?
And where i need to go in my azure portal to see the logs there after
deployment.
I tried to go in Function App - open my function and there the azure
function but i can't see any logs there...
Of course, you can get the log files on local. I assume you are based on windows, then just edit the host.json like this:
{
"version": "2.0",
"logging": {
"fileLoggingMode": "always",
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
And go to
C:\Users\yourusernameonlocal\AppData\Local\Temp\LogFiles\Application\Functions\Function\yourfunctionname
After that you will see the log files.:)
This should probably resolve your issue.
Azure Functions JavaScript developer guide:
Don't use console.log to write trace outputs. Because output from console.log is captured at the function app level, it's not tied to a specific function invocation and isn't displayed in a specific function's logs.

ServiceBus binding breaks Node.js Azure Function

I have simple azure function which is triggered by http
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
context.res = {
// status: 200, /* Defaults to 200 */
body: "Success"
};
}
function.json
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
At this point I can trigger the function and see the response.
Then I try to add a service bus binding to function.json
{
"bindings": [
...
{
"type": "serviceBus",
"direction": "out",
"name": "outputSbTopic",
"topicName": "topicName",
"connection": "ServiceBusConnection"
}
]
}
When I add the binding the function returns 404 and there is nothing in log. I've even not started to use the binding.
What can be wrong? I'm struggling with the issue more than 2 hours and have no more ideas.
host.json (just in case)
{
"version": "2.0",
"extensions": {
"serviceBus": {
"prefetchCount": 100,
"messageHandlerOptions": {
"autoComplete": true,
"maxConcurrentCalls": 32,
"maxAutoRenewDuration": "00:05:00"
}
}
}
}
Runtime version ~2
Node.js Version Node.js 12 LTS
App is run in read only mode from a package file.
AppType functionAppLinux
UPDATE
I created the function with VS Code Azure Function Extension and deployed with DevOps. Later I created function in azure portal manually. Compared with App Service Editor files of both functions and found out that my first function doesn't have extensionBundle in host.json. That was the reason.
Use your host.json also get the same problem:
The problem seems comes from the host.json in your function app.
On my side those files is:
index.js
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
var message = "This is a test to output to service bus.";
context.bindings.testbowman = message;
context.done();
context.res = {
status: 200,
body: "This is a test to output to service bus topic."
};
};
function.json
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
},
{
"name": "testbowman",
"type": "serviceBus",
"topicName": "testbowman",
"connection": "str",
"direction": "out"
}
]
}
host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"str":"Endpoint=sb://testbowman.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxx="
}
}
And it worked:

Azure function prints out the http error message

I have been trying to execute an azure function. The function does some calculation and returns a json response. If I just print out the json, it gets printed, but the log also contain the below error statement:
2020-06-05T05:03:35.256 [Error] Executed 'Functions.curvefitting' (Failed, Id=8b47fa39-746e-4153-9451-d18bb79ed4cd)
Unable to cast object of type 'System.Byte[]' to type 'Microsoft.AspNetCore.Http.HttpRequest'.
I have coded my main function as:
import azure.functions as af
def main(myblob: af.InputStream) -> str:
json_response = <some calculatios>
return json_response
And here's my function.json file:
{
"scriptFile": "xyz.py",
"entryPoint": "main",
"bindings":[
{
"authLevel": "function",
"type": "blobTrigger",
"direction": "in",
"name": "myblob",
"path": "xyz.xlsx",
"connection": "AzureWebJobsStorage",
"methods":[
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
Please let me know what I am doing wrong here. I am new to azure functions.
Based on your Json file it looks like you started out with an HttpTriggered function, but you changed it to a BlobTriggered function. Your input binding defines a blobTrigger, but there's also methods there (which are HTTP methods) and the output binding is an HTTP binding.
Most important question is: what are you trying to achieve? If this should be an HttpTriggered function that uses a Blob as input, define an HttpTrigger and an input binding for the blob.
This would be an example of an HttpTriggered Function with an input Blob binding:
{
"scriptFile": "xyz.py",
"entryPoint": "main",
"bindings":[
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req"
},
{
"name": "myblob",
"type": "blob",
"dataType": "binary",
"path": "xyz.xlsx",
"connection": "MyStorageConnectionAppSetting",
"direction": "in"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
Your main entry point would look something like
def main(req: func.HttpRequest, myblob: func.InputStream) -> func.HttpResponse:
For more information and examples, see Azure Blob storage input binding for Azure Functions and Azure Functions HTTP trigger.

How to insert data in cosmos DB with azure JavaScript function app?

I am trying to insert data from azure javascript function app to cosmos DB.
This is the function.json File
{
"bindings": [
{
"type": "cosmosDBTrigger",
"name": "documents",
"direction": "in",
"leaseCollectionName": "leases",
"connectionStringSetting": "CosmosDBConnection",
"databaseName": "roi",
"collectionName": "reports",
"createLeaseCollectionIfNotExists": "true"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
index.js have a code like this.
module.exports = async function (context, documents) {
if (!!documents && documents.length > 0) {
context.log('Document Id: ', documents[0].id);
}
}
Below images will have the error in the application.
Is there any function or query to insert the data ? the request data which is coming from api will look like this.(its coming in rawBody property of request)
When i am fetching the data its workign fine.
{
"name": "inputDocumentIn",
"type": "cosmosDB",
"databaseName": "roi",
"collectionName": "reports",
"sqlQuery": "SELECT * from reports r",
"connectionStringSetting": "CosmosDBConnection",
"direction": "in"
}
local.setting.json file
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"AzureWebJobsDashboard": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"CosmosDBConnection": "AccountEndpoint=.....;"
},
"Host": {
"LocalHttpPort": 7071,
"CORS": "*"
}
}
With this azure value in local.setting.ts file , i m getting following error.
Please check if the Connection String is pointing to the correct account and check if it was caused by the firewall and networks. Go to your cosmos db account on azure portal and click "Firewall and virtual networks". You can select "All networks" or "Selected networks" with your current IP filled in it.
This sounds like some some dependency conflict. Could you do a dotnet clean on the project folder and then verify that all projects (in case you have project dependencies) have the latest version of the Microsoft.Azure.WebJobs.Extensions.CosmosDB package (currently 3.0.5)?
The solution of the above problem is :
I have changed function.json file with this code.
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"methods": [ "post" ],
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "res"
},
{
"type": "cosmosDB",
"name": "outputDocument",
"databaseName": "roi",
"collectionName": "reports",
"createIfNotExists": true,
"connectionStringSetting": "CosmosDBConnection",
"direction": "out",
"partitionKey": "/id"
}
],
"disabled": false
}
and the request coming from front end will be manipulate like this.
module.exports = function (context, req) {
if (req.body) {
context.bindings.outputDocument = req.body;
var responseBody = {};
responseBody.message = "Wow! data with id '" + req.body.id + "' was created!";
context.res = {
status: 201,
body:responseBody
};
}
else {
context.res = {
status: 400,
body: { "message" : "Please pass a valid object in the request body"}
};
}
context.done();
}

Use Azure Functions with trigger http, input DocumentDB using ID based from http request

So what I read from this page, is that I should be able to have:
trigger HTTP
input Http request
input DocumentDb
output DocumentDb
Numbers 1, 2 and 4 are working. But how to get a document from DocumentDB with the ID from the path?
Can I use the {path} from the proxy-route in my DocumentDb Input?
I have a proxy defined like so.
{
"$schema": "http://json.schemastore.org/proxies",
"proxies": {
"index": {
"matchCondition": {
"route": "{*path}",
"methods": [
"GET"
]
},
"backendUri": "https://%WEBSITE_SITE_NAME%.azurewebsites.net/api/Index"
},
"api": {
"matchCondition": {
"route": "api/{*path}"
},
"backendUri": "https://%WEBSITE_SITE_NAME%.azurewebsites.net/api/{path}"
},
"index existing subscription": {
"matchCondition": {
"route": "/subscription/{*path}",
"methods": [
"GET"
]
},
"backendUri": "https://%WEBSITE_SITE_NAME%.azurewebsites.net/api/IndexSubscription/{path}"
}
}
}
Here is an example of a Function with Document DB input binding.
function.json
{
"bindings": [
{
"authLevel": "function",
"name": "req",
"type": "httpTrigger",
"direction": "in",
"route": "MyDocFunc/{docid}"
},
{
"type": "documentDB",
"name": "inputDocument",
"databaseName": "MyDocDB",
"collectionName": "MyCollection",
"id": "{docid}",
"connection": "mydocdb_DOCUMENTDB",
"direction": "in"
},
{
"name": "$return",
"type": "http",
"direction": "out"
}
],
"disabled": false
}
csx
public static async Task<HttpResponseMessage> Run(
HttpRequestMessage req, string docid, string inputDocument)
{
return req.CreateResponse(HttpStatusCode.OK, inputDocument);
}
The usage of proxy doesn't affect this much... You can pass your proxy parameter to function parameter.

Resources