Sending Multiple SMS Messages in Twilio Reply - python

I am writing software using the Twilio API, Flask, and Python to send and receive SMS messages. When I reply to a message, I also want to send out a message to a different phone number (thereby sending 2 messages in total, one to the original sender, and one to an entirely different individual).
I reply to an SMS using:
#app.route("/", methods=['GET', 'POST'])
def reply():
# Send other text
sendMessage(to_number, text)
# Send response
resp = twilio.twiml.Response()
resp.sms(response)
return str(resp)
Where the sendMessage function is:
from twilio.rest import TwilioRestClient
def sendMessage(to_number, text):
ACCOUNT_SID = "XXXXXXXXX"
AUTH_TOKEN = "XXXXXXXX"
twilioNumber = "XXXXXXXXX"
client = TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN)
client.messages.create(
to=to_number,
from_=twilioNumber,
body=text,
)
But the sendMessage function does not actually send a text to the separate number (note the reply still works). Note also that the sendMessagefunction works fine when it is called outside of the reply function.
How should I go about sending two different texts to two different numbers in response to a text from only one of those numbers?

This worked for me to send the same message to multiple numbers:
from twilio.rest import TwilioRestClient
def sendMessage(text):
ACCOUNT_SID = "ACXXXXXXXX"
AUTH_TOKEN = "YYYYYYYYYY"
twilioNumber = "+15551235554"
client = TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN)
NUMBERS = {
'Foo':'+15551235555',
'Bar':'+15551235556'
}
for name, number in NUMBERS.items():
message = client.messages.create(
to=number,
from_=twilioNumber,
body=text)
print message.sid
Maybe you can find a way to adapt this to your specific needs. Note that Twilio limits your outbound SMS to 1 SMS message segment per-second, per-number. More info on Rate-Limits

You can send multiple responses to a user reply by calling the MessagingResponse() method. I used a list to store multiple messages and then I looped over the list to send each message as it is shown below.
def incoming_message() -> str:
'''
Receive incoming messages
'''
# Get the message the user sent our Twilio number
incoming_message = request.values.get('Body', '').lower()
# Get the phone number of the person sending the text message
phone_number = request.values.get('From', None).replace('whatsapp:', '')
if validate_phone_number(phone_number):
# Get the message the user sent our Twilio number
resp = MessagingResponse()
# Determine the right reply for this message
# msg = resp.message()
# Query the database for the phone number
if incoming_message:
# deconcatenate the list of messages and send them as different messages
for message in conversations(phone_number, incoming_message):
msg = resp.message(message)
else:
pass
else:
msg.body("Lo sentimos, no se encuentra registrado en nuestro sistema. Por favor comuniquese con nosotros para poder ayudarlo.")
return str(resp)
def conversations(phone_number: str, incoming_message: str) -> list:
'''
Conversations with the user
'''
messages = list()
client = Client.query.filter_by(phone=phone_number).first()
if incoming_message:
match incoming_message:
case 'hola':
messages = [
f'¡Hola {client.name}! Gracias por hacer tu reservación con nosotros 😃', 'cómo podemos ayudarte?']
case 'adios':
messages.append(
f'¡Adios {client.name}! Esperamos verte pronto 😃')
case 'menu':
messages.append(
f'¡Hola {client.name}! Estos son los servicios que ofrecemos: \n 1. Ubicacion \n 2. Reservacion \n 3. Cancelar reservacion \n 4. Salir')
case _:
messages.append(
f'No pude entender tu respuesta 😟 Inténtalo nuevamente 👇🏼 o escribe menu para desplegar las opciones con las que podemos apoyarte.')
# return the list of messages in different messages
return messages
else:
pass

Related

Flask-Email creates multiple threads when sending emails to many users in a loop

I have a flask application. I have written a loop which goes through a database and looks for users and based on some conditions sends emails to them.
for receiver in new_receivers:
user = User.query.filter_by(organization=receiver).first()
send_email(subject='You have new messages!',
sender='mail#mail.com',
recipient=user.email,
text_body= 'test',
html_body= 'test')
Sending email creates a new thread for sending email like this:
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
def send_email(subject : str , sender : str , recipient : str , text_body='' , html_body='')->None:
msg = Message(subject, sender=sender, recipients=[recipient])
msg.body = text_body
msg.html = html_body
Thread(target=send_async_email, args=(app, msg)).start()
Is there a way to avoid creating hundreds of threads, but pass a list of emails to the thread and loop sending in here?
I collected messeges to list and passed them to thread, where send them in a loop.
emails = []
for receiver in new_receivers:
user = User.query.filter_by(organization=receiver).first()
emails.append(
{
"subject" : 'You have new messages!',
"sender" : 'mail#mail.com',
"recipient" : user.email,
"text_body" : 'test',
"html_body" : 'test'
}
)
meseges = []
for email in emails:
msg = Message(email["subject"], sender=email["sender"], recipients=email["sender"])
msg.body = email["text_body"]
msg.html = email["html_body"]
meseges.append(msg)
def send_async_email(app, msgs):
with app.app_context():
for msg in msgs:
mail.send(msg)
def send_messeges(messegs)->None:
Thread(target=send_async_email, args=(app, messegs)).start()

Emails sent with the Gmail API are not grouped in threads?

I am using the gmail API for sending emails. This is the function I am using to create an email:
def createEmailNoAttachments(self, send_to_emails, subject_text, main_message_text, msgID=None, inReplyTo=None, html=False):
try:
fromEmail = self.from_email_total
if (type(main_message_text) == list) or (type(main_message_text) == tuple):
total_text = ""
for line in main_message_text:
if type(line) == str:
total_text = total_text + line + "\n"
main_message_text = total_text
mimeMessage = MIMEMultipart()
if type(send_to_emails) == list:
mimeMessage['to'] = ", ".join(send_to_emails)
else:
mimeMessage['to'] = send_to_emails
mimeMessage['from'] = fromEmail
mimeMessage['subject'] = subject_text
if inReplyTo != None:
mimeMessage["In-Reply-To"] = inReplyTo
mimeMessage["References"] = inReplyTo
if msgID != None:
mimeMessage['Message-ID'] = msgID
if html:
msg= MIMEText(main_message_text, 'html')
else:
msg= MIMEText(main_message_text, "plain")
mimeMessage.attach(msg)
raw = base64.urlsafe_b64encode(mimeMessage.as_bytes())
raw = raw.decode()
body = {'raw': raw}
return body
except:
self.myLogger.error("An error was encountered while attempting to create gmail email")
tb = traceback.format_exc()
self.myLogger.exception(tb)
return False
I then send the email with
def gmailAPISendEmail(self, email_message, deleteFromInbox=False, userID="me"):
try:
self.refreshGmailService()
self.myLogger.info("Attempting to send email message")
request = self.service.users().messages().send(userId=userID, body=email_message)
response = self.executeGmailAPI_withretry(request=request)
if response == False:
self.myLogger.error("An error occurred in executeGmailAPI_withretry while trying to send email message")
return False
else:
try:
responseID = str(response['id'])
if deleteFromInbox == True:
delete_result = self.deleteEmail(emailID=responseID)
if delete_result == False:
self.myLogger.error(f"An error occurred in deleteEmail with responseID ({responseID})")
self.myLogger.info("Successfully sent email message with ID (" + responseID +")")
return responseID
except:
return "CouldNotExtractID"
except:
self.myLogger.error("An error occurred in gmailAPISendEmail")
tb = traceback.format_exc()
self.myLogger.exception(tb)
return False
The problem I am noticing is that similar emails with the same email subject and same sender and recipient are not being grouped under one thread when sent using the above functions (the gmail API). In the recipient email inbox, each individual email appears separately, even though they have the same subject and same sender and receiver email addresses.
I believe the next step would be to manually assign threadid. However, this is far from ideal, as I would need to incorporate some logic to do all of this.
Before when I used SMTP, I didn't have to set a threadid or anything like that. When sending emails with SMTP, emails would automatically group together based on same email subject and same recipient.
Nothing changed between before and now, except that I am sending the same emails with the gmail API in place of SMTP.
Why doesn't the gmail API behave similar to SMTP, even though I am creating the email very similarly? Is there something I can do to have Gmail inboxes to group the emails just like SMTP, without having to build logic and keeping track of threadids?
From sending
If you're trying to send a reply and want the email to thread, make sure that:
The Subject headers match
The References and In-Reply-To headers follow the RFC 2822 standard.
For information on sending a message from a draft, see Creating Drafts.
So you need the message id of the original message you are replying to. This is not the same as thread id.
message['In-Reply-To'] = message_id
message['References'] = message_id

Welcome Message isn't work because GetUpdates Telegram Bot API can't record joined notification update in supergroup

Few days ago i made a telegram bot with python using api from https://core.telegram.org/bots/api.
All the code works perfectly until i realize that the GetUpdates api didn't record the joined notification for the new user in my group
My plan is to made a welcome message to new user based on those record. The group not allowing user to send message (broadcast group) and right now i confused that i can't get any single record related to the new user joined, so then the welcome message didn't work perfectly
This is my function for getUpdates api and the welcome message
def get_updates(self, offset=0, timeout=50):
method = 'getUpdates'
params = {'timeout': timeout, 'offset': offset}
resp = requests.get(self.api_url + method, params)
result_json = resp.json()['result']
return result_json
def welcome_msg(self, item):
chat_id = item["message"]["chat"]["id"]
user_id = item["message"]["new_chat_member"]["id"]
if "username" in item["message"]["new_chat_member"]:
user_name = item["message"]["new_chat_member"].get("username", user_id)
else:
user_name = item["message"]["new_chat_member"].get("first_name", user_id)
welcom_msg = "HI WELCOME TO THIS GROUP"
to_url3 = 'https://api.telegram.org/bot{}/sendMessage?chat_id={}&text={}&parse_mode=HTML&disable_web_page_preview=True'.format(token, chat_id, welcom_msg)
resp3 = requests.get(to_url3)
And after that the welcome message should be like this
new_offset = 1
all_updates = get_updates(new_offset)
if len(all_updates) > 0:
for current_update in all_updates:
first_update_id = current_update['update_id']
if old_id < first_update_id:
old_id = int(current_update['update_id'])
try:
if "new_chat_member" in current_update['message']:
welcome_msg(current_update)
chat_id = current_update["message"]["chat"]["id"]
message_id = current_update["message"]["message_id"]
new_offset = first_update_id + 1
except:
pass
Does the restriction of the group (member can't send message) made the getUpdates API couldn't work and the welcome message didn't showing up???
Go to botfather, bot settings and set privacy mode off for this bot, It should work

How do I send emails to multiple people with different body?

I want to group recipients by reason and sent out tailored emails for each reason. The data looks like this.
Email reason
0 one#outlook.com Address
1 two#outlook.com Address
2 three#outlook.com Phone Number
3 one#outlook.com Postcode
import Pandas as pd
data = { 'Email': ['one#outlook.com','two#outlook.com','three#outlook.com','one#outlook.com'],
'reason': ['Address','Address', 'Phone Number','Postcode']}
df = pd.DataFrame(data)
df
This is how I started.
for e in df['reason'].unique():
print(f"Reason: {e}")
print(df[df['reason'] == e]['Email'].to_list())
print('\n')
Reason: Address
['one#outlook.com', 'two#outlook.com']
Reason: Phone Number
['three#outlook.com']
Reason: Postcode
['one#outlook.com']
Not sure how to use this list below.
message = "Update"
email_subject = "Test"
recipients = e
# sending email function
def send_mail(text, subject, recipients):
o = win32com.client.Dispatch("Outlook.Application")
Msg = o.CreateItem(0)
Msg.to = ''
Msg.BCC = "; ".join(recipients)
Msg.Subject = subject
Msg.HTMLBody = text
Msg.Send()
# sending email
send_mail(message,email_subject,recipients)
How to set 3(or more) different email body's and loop around the grouped list to sent separate emails for each reason?
You need to repeat the following code in the loop:
Msg = o.CreateItem(0)
Msg.to = recipient;
Msg.Subject = subject
Msg.HTMLBody = text
Msg.Send()
where recipient is an email address of a single recipient.
You may find the Using Visual Basic for Applications in Outlook article helpful.

Errors receiving emails with imaplib, from a specific inbox

When reading emails from a specific folder (Office365), the body of the message is a random long string that makes no sense.
Initially, I sent those emails to my personal mail as copy, to a specific folder. Reading from there I haven't had problems.
But when I try to read directly from the main inbox, the messages are long strings that makes no sense (so, I can´t parse anything)
mail = imaplib.IMAP4_SSL(SMTP_SERVER)
mail.login(FROM_EMAIL, FROM_PWD)
boxes = mail.list()
mail.select('INBOX/netstatus', readonly=True)
(type, data) = mail.uid('SEARCH', None, '(UNSEEN)')
mail_ids = data[0]
id_list = mail_ids.split()
def read_email(self, *id_list):
id_list = list(id_list)
for i in reversed(id_list):
(typ, data) = mail.uid('FETCH', i, '(RFC822)')
for response_part in data:
if isinstance(response_part, tuple):
print("Response: ",response_part)
msg = \ email.message_from_string(response_part[1].decode('utf-8'))
body = ''
email_subject = msg['subject']
email_from = msg['from']
email_date = msg['date']
message= msg.get_payload().encode('utf-8')
print(message)
I receive something like this when I read from my personal inbox:
mymail: b'Status from Device (x.x.x.x) to AnotherDevice (y.y.y.y), interface A B, in Protocol came up\r\n'
But when I read from the main inbox:
'QWRq4N5IGZyb20gVVREFxLXJlMSAuMTAuMjUsIDAxMDAuMTAwMS4w\r\nMDI1LjAwKSB0byBVU0FEQUxIERS4MC4xMC4xMMDAxLjAw\r\nMjUuMDQpLCBpbnZhY2UgMTAuMTA4AuMjI5IHRvIDEwLjEwLjIwLjEzMCwgaW4gSVNJUy9M\r\nZXZlbDIgd2VudCBkkNvbmZ3VyZWQgd2F0Y2hsaXN0OiI1OQ0K\r\n'
With Python3.6 or later, you can use EmailMessage.get_content() to decode the encoded content automatically.
import email
from email import policy
# Email based on one of the examples at https://docs.python.org/3.6/library/email.examples.html
s = """Subject: Ayons asperges pour le =?utf-8?q?d=C3=A9jeuner?=
From: =?utf-8?q?Pep=C3=A9?= Le Pew <pepe#example.com>
To: Penelope Pussycat <penelope#example.com>,
Fabrette Pussycat <fabrette#example.com>
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
MIME-Version: 1.0
ICAgIFNhbHV0IQoKICAgIENlbGEgcmVzc2VtYmxlIMOgIHVuIGV4Y2VsbGVudCByZWNpcGllWzFd
IGTDqWpldW5lci4KCiAgICBbMV0gaHR0cDovL3d3dy55dW1tbHkuY29tL3JlY2lwZS9Sb2FzdGVk
LUFzcGFyYWd1cy1FcGljdXJpb3VzLTIwMzcxOAoKICAgIC0tUGVww6kKICAgIAo=
"""
msg = email.message_from_string(s, policy=policy.default)
print(msg.get_content())
Result:
Salut!
Cela ressemble à un excellent recipie[1] déjeuner.
[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718
--Pepé
For multipart messages you need to iterate over the parts:
for part in msg.iter_parts():
print(part.get_content())

Categories

Resources