How to send Properties details in EventHub message using python? - python

I am referring to this article "https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-python-get-started-send" related to sending messages to EventHub using Python.
A Message has the following components: offset, body, systemProperties, properties.
offset is auto-generated but we can provide the other.
For my project - apart from message body I also need to send "Properties" which is not part of Body, How to do that? I checked the class EventData(object): and looks like application_properties can be used to do this but i'm not sure how to implement this.
Is application_properties right analogy to obtain "Properties" in message?
Could you please add more details to the article with example displaying how to use the python EventData class for sending detailed information apart from message body like Properties and SystemProperties. As of now Properties is being sent as empty list.
Sample message format that i need to send to EventHub using Python:
Sender.send(EventData('{"**offset**":"2415248","**body**":"TESTone:100,
Temperature:553.0","**systemProperties**":[{"key":{"string":"x-opt-
sequence-number"},"value":{"string":"23512"}},{"key":{"string":"x-opt-
offset"},"value":{"string":"2415248"}},{"key":{"string":"x-opt-
enqueued-time"},"value":{"string":"Fri Feb 22 02:14:23 UTC
2019"}}],"**properties**":[]}'))
And I want to send this dict values in properties: {"key":{"string":"Type"},"value":{"string":"iPhone"}}

I asked this question elsewhere as the solution provided by PraveenS does not actually solve the problem. The correct answer which I received is below, sharing to help others:
The solution is to assign the properties you want to be sent with the message to EventData.properties, applying that to the above code would look like this:
from azure.eventhub import EventHubClient, Receiver, Offset, Sender, EventData
from uamqp import Message
ADDRESS = "amqps://<>.windows.net/<>"
USER = "RootManageSharedAccessKey"
KEY = "<>"
client = EventHubClient(ADDRESS, debug=True, username=USER, password=KEY)
Sender = client.add_sender(partition="0")
client.run()
event = EventData(body="TESTTWO:100, Temperature:-127.0")
### THIS IS WHERE THE CHANGE IS ###
event.properties = {"Type": "iPhone"}
Sender.send(event)

Found solution to this, yes we can use "application_properties" to send "properties" of message.
This is my sample code that worked:
from azure.eventhub import EventHubClient, Receiver, Offset, Sender, EventData
from uamqp import Message
ADDRESS = "amqps://<>.windows.net/<>"
USER = "RootManageSharedAccessKey"
KEY = "<>"
client = EventHubClient(ADDRESS, debug=True, username=USER, password=KEY)
Sender = client.add_sender(partition="0")
client.run()
event = EventData(body="TESTTWO:100, Temperature:-127.0")
event.application_properties = {"Type": "iPhone"}
Sender.send(event)

You may also find useful the following way, which basically do the same:
props = {"Type": "iPhone"} # properties you want to send
columns = ['body', 'properties']
values = [(write_binneddata, props)] # You can also send multiple messages adding tuples to the list
df = spark.createDataFrame(values, columns)
conn_string = f"Endpoint=sb://{event_hub_namespace}.servicebus.windows.net/;SharedAccessKeyName={shared_acc_keyname};SharedAccessKey={shared_acc_key};EntityPath={event_hub_name}"
conf = { 'eventhubs.connectionString' : conn_string }
ds = (
df
.write
.format("eventhubs")
.options(**conf)
.option("checkpointLocation", f"{checkpoint_path}")
.save()
)
PS: it needs this library installed.

Related

Transfer an email with Python

I've tried with no conclusions to resend emails with Python.
Once I've logged in SMTP and IMAP with TLS, this is what I have written:
status, data = self._imapserver.fetch(id, "(RFC822)")
email_data = data[0][1]
# create a Message instance from the email data
message = email.message_from_string(email_data)
# replace headers (could do other processing here)
message.replace_header("From", 'blablabla#bliblibli.com')
message.replace_header("To", 'blobloblo#blublublu.com')
self._smtpserver.sendmail('blablabla#bliblibli.com', 'blobloblo#blublublu.com', message.as_string())
But the problem is that the variable data doesn't catch the information from the email, even if the ID is the one I need.
It tells me:
b'The specified message set is invalid.'
How can I transfer an email with Python?
Like the error message says, whatever you have in id is invalid. We don't know what you put there, so all we can tell you is what's already in the error message.
(Also, probably don't use id as a variable name, as you will shadow the built-in function with the same name.)
There are additional bugs further on in your code; you need to use message_from_bytes if you want to parse it, though there is really no need to replace the headers just to resend it.
status, data = self._imapserver.fetch(correct_id, "(RFC822)")
self._smtpserver.sendmail('blablabla#bliblibli.com', 'blobloblo#blublublu.com', data[0][1])
If you want to parse the message, you should perhaps add a policy argument; this selects the modern EmailMessage API which was introduced in Python 3.6.
from email.policy import default
...
message = email.message_from_bytes(data[0][1], policy=default)
message["From"] = "blablabla#bliblibli.com"
message["To"] = "blobloblo#blublublu.com"
self._smtpserver.send_message(message)
The send_message method is an addition to the new API. If the message could contain other recipient headers like Cc:, Bcc: etc, perhaps using the good old sendmail method would be better, as it ignores the message's headers entirely.

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.

Receive and Print a Twilio SMS with Python

For clarification, I don't want to reply to the SMS. Every tutorial or document I've looked at is about setting up a port to listen on.
What I'm trying to do is just get the SMS and print it. I can send them fine and without problems.
Here is my sending function, and it works.
def send():
message = client.messages \
.create(
body=sendMSG,
from_='MY_TWILIO_NUMBER',
to='MY_PERSONAL_NUMBER'
)
print(message.sid)
How would you receive an SMS without Flask? Is there a way to do something similar to this method below just for receiving?
def receive():
message = client.messages \
.recieve(
from_='MY_PERSONAL_NUMBER',
to='MY_TWILIO_NUMBER'
)
print(message.sid)
I have not personally tried to get SMS messages from the logs before, always getting it directly through a webhook, but from what I see, it appears the command you might be looking for is list(). You can add filters, as shown in the API docs, and there are three filtering options. You can filter by DateSent, To, or From.
I have not tried this, but it would seem that the way to use this would be the following (adjusted from the code they supply):
# Download the helper library from https://www.twilio.com/docs/python/install
from twilio.rest import Client
# Your Account Sid and Auth Token from twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)
messages = client.messages.list(from='MY_PERSONAL_NUMBER', to='MY_TWILIO_NUMBER')
for record in messages:
print(record.sid)
If that doesn't work, the variables they use are actually capitalized "To" and "From", so you might try that.
After looking at that a bit, you might be looking more for this:
received = client.messages.list(to='MY_TWILIO_NUMBER')
sent = client.messages.list(from='MY_PERSONAL_NUMBER')
That will separate out those sent to you, and those sent from you

schedule email with sendgrid python

I am using python module of sendgrid (https://github.com/sendgrid/sendgrid-python) to send transactional emails. I need help with the syntax to send the email at a scheduled time.
The general sendgrid documentation asks to modify json as "{ “send_at”: 1409348513 }". I believe this json is not directly accessible in sendgrid-python. I need syntax for doing equivalent thing with the python library.
My current code is equivalent to the one copied below. It would be great if some one can suggest how to modify this code to schedule it at a particular time e.g. datetime.dateime.now() + datetime.timedelta(days=1)
import sendgrid
from sendgrid.helpers.mail import Email, Content, Substitution, Mail
import urllib2 as urllib
def send_email_custom():
sg = sendgrid.SendGridAPIClient(apikey=myApiKey)
from_email = Email(sendEmail)
to_email = Email(custEmail)
reply_to_email = Email(receiveEmail)
content = Content("text/html", "Introduction")
mail = Mail(from_email, subject="Hi!", to_email=to_email, content=content)
mail.personalizations[0].add_substitution(Substitution("_firstName_", firstName))
mail.set_template_id(templateId)
try:
response = sg.client.mail.send.post(request_body=mail.get())
except urllib.HTTPError as e:
print(e.read())
return False
if response.status_code >=200 and response.status_code < 300:
return True
else:
return False
send_at is a component of the personalizations Object, so you can define it at that level, allowing you to set distinct sending times for each recipient/personalization set.
If you don't need that, you can also set it at the top mail level.
Looks like you should be able to do that by following this example. You can specify all of the raw fields you need.
Exact code solution:
mail = Mail(from_email, subject="Hi!", to_email=to_email, content=content)
mail.send_at = SendAt(1461775053) # Time is specified in UNIX form.
# This takes advantage of Sendgrid's inbuilt email scheduler
# but you can't schedule more than 72 hours in advance.
This removes the need to deal with personalizations for send time.
Source: line 308 of https://github.com/sendgrid/sendgrid-python/blob/main/examples/helpers/mail_example.py
Posting this for those who Googled their way here in 2022 or later.

How to email to multiple users via x-smtpapi?

I am utilising both sendgrid-python and smtpapi-python libraries.
sg = sendgrid.SendGridClient('xx', 'xxx', raise_errors=True)
message = sendgrid.Mail()
message.set_subject('yyyy')
with open("../template/s_letter.html", "r") as myfile:
message.set_html(myfile.read())
message.set_from('xx#xx.org')
message.add_to("xx#xx.com")
header = SMTPAPIHeader()
test_emails = ['xxx#xxx.com', 'xx.xxx#xxx.com']
header.set_tos(test_emails)
message.set_headers(header.json_string())
status, msg = sg.send(message)
I am trying to set the x-smtpapi header in order to send the same email to multiple users.
However I get the exception.
sendgrid.exceptions.SendGridClientError: (400, '{"message": "error", "errors": ["JSON in headers is valid but incompatible"]}')
Any idea what I am overlooking?
The SendGrid Python Library in-fact already implements smptpapi-python and passes the methods through to the larger library. So, message.add_to() is header.add_to(). For this reason, you should only need sendgrid-python. Which you may implement as follows:
sg = sendgrid.SendGridClient('xx', 'xxx', raise_errors=True)
message = sendgrid.Mail()
message.set_subject('yyyy')
with open("../template/s_letter.html", "r") as myfile:
message.set_html(myfile.read())
message.set_from('xx#xx.org')
test_emails = ['xxx#xxx.com', 'xx.xxx#xxx.com']
message.set_tos(test_emails)
status, msg = sg.send(message)
This is a very late reply but I came across this issue today and after heading up all day I got a solution which I am posting below if anybody lands on this question.
With the message Instance use smtpapi like below:
message.smtpapi.add_to(test_emails)

Categories