I have 2 functions that uses Twilio to send media files and text messages respectively. Most times, I want to send photo then a text message. However, when I call both functions, the text message sends before the photo. How do I ensure that the photo sends first before the text.
//sends photo
public static function sendMediaMessage($phone, $mediaUrl, $msg = null){
try{
$client = new Client(env('TWILIO_SID'), env('TWILIO_TOKEN'));
$send = $client->messages->create(
"whatsapp:".$phone,
array(
'from' => "whatsapp:".env('TWILIO_NUMBER'),
'body' => $msg,
'mediaUrl' => [$mediaUrl],
)
);
}catch (\Exception $exception){
}
}
//send text messages
public static function sendWhatsAppMessage($phone, $message){
try{
$client = new Client(env('TWILIO_SID'), env('TWILIO_TOKEN'));
$send = $client->messages->create(
"whatsapp:".$phone, // Text this number
array(
'from' => "whatsapp:".env('TWILIO_NUMBER'),
'body' => $message
)
);
}catch (\Exception $exception){
}
}
Makes call
myClass::sendMediaMessage();
myClass::sendWhatsAppMessage();
Twillio documentation suggests you can supply a callback url using the statusCallback field.
If specified, we POST these message status changes to the URL: queued, failed, sent, delivered, or undelivered.
You could configure a route for it and then send the second message.
Alternatively you could look into the message feedback system Twillio has in place.
To track message feedback, you must set ProvideFeedback=true when you first create the Message. This will create a Message Feedback instance with an Outcome of unconfirmed.
I'm not sure which of the above should be used, that's up to you.
Related
I am trying to create a chatbot using laravel php and Twilio Api. I am still in sandbox. This the code i currently have
public function commandHandler(Request $request){
$from = $request->input('From'); // phone number where the message is coming from
$body = $request->input('Body');// what user wrote
$client = new \GuzzleHttp\Client();
try {
$response = $client->request('GET', "https://api.github.com/users/$body"); //test if network is working
if ($response->getStatusCode() == 200) {
$message = "Welcome to System. \n";
$message .= "To Log In, Enter Email Address";
$this->sendWhatsAppMessage($message, $from);
} else {
$this->sendWhatsAppMessage("Error", $from);
}
} catch (RequestException $th) {
$response = json_decode($th->getResponse()->getBody());
$this->sendWhatsAppMessage($response->message, $from);
}
return;
}
I can get what user has typed from the variable $body and send user back a message through the function
$this->sendWhatsAppMessage($response->message, $from);
but the problem is when i want the user to enter password, it goes to the same url and does the same functions of which i would like for it to do different functions. Twilio only accepts one call-back url which i have to use that one function only. How do i use different functions for different messages sent to the user
this is what is in my api.php
Route::post('/chat', 'App\Http\Controllers\ChatBotController#listenToReplies');
and that is the url in the callback of the Twilio dashboard
Is there a way to make this work..
I'm trying to publish a 'PING' request to a device, and then subscribe to another channel and wait for the 'PONG' response. Here's the code:
public function ping(Request $request)
{
$device = Device::find($request->id);
if ($device) {
//Listen on laravel_device_DEVICEID
$listen_topic = 'laravel_device_' . $device->device_id;
$result = [];
$mqtt = MQTT::connection();
$mqtt->subscribe($listen_topic, function (string $topic, string $message) use ($mqtt, &$result) {
$result['topic'] = $topic;
$result['message'] = $message;
$mqtt->interrupt();
}, 0);
$mqtt->loop(true, true);
//Submit PING message
$topic = $device->device_id;
$message = json_encode([
'type' => 'ping',
'device_id' => $device->device_id
]);
$mqtt = MQTT::connection();
$mqtt->publish($topic, $message);
$device->last_ping_response = 2;
$device->save();
}
}
I'm so free to copy my response from the original question in the php-mqtt/laravel-client repository.
Yes, it is possible and a fairly common thing to do as well. The pattern is called RPC (Remote Procedure Call).
Your code already looks quite good, the only issue is the order of subscribe(), publish() and loop(). Subscribing first is cruicial, since you do not want to miss a response before your subscription goes through. This part is correct already. But you may start the loop only after publishing the request, otherwise the publish() is never reached (because the loop does not exit by itself, only when it receives a message).
Here is the updated piece of code of yours, with some best practices added in. I assumed the response message is what you want to save as $device->last_ping_response:
use PhpMqtt\Client\MqttClient;
use PhpMqtt\Client\Exceptions\MqttClientException;
public function ping(Request $request)
{
$device = Device::find($request->id);
// Exit early if we have no device to ping. Doing it this way round,
// we save one level of identation for the rest of the code.
if ($device === null) {
return;
}
// Prepare all data before connecting to the broker. This way, we do not waste
// time preparing data while already connected.
$subscribeTopic = "laravel_device_{$device->device_id}";
$publishTopic = $device->device_id;
$request = json_encode([
'type' => 'ping',
'device_id' => $device->device_id,
]);
try {
$mqtt = MQTT::connection();
// Ensure we are ready to receive a response to the request
// we are going to send.
$mqtt->subscribe(
$subscribeTopic,
function (string $topic, string $message) use ($mqtt, $device) {
// Update the device based on the response.
$device->last_ping_response = $message;
$device->save();
$mqtt->interrupt();
},
MqttClient::QOS_AT_LEAST_ONCE
);
// Here we register a timeout using a loop event handler.
// The event handler is passed the elapsed time
// the loop runs already (in seconds).
// We do this because in case the receiver of our request is offline,
// we would be stuck in a loop forever.
$mqtt->registerLoopEventHandler(
function function (MqttClient $client, float $elapsedTime) {
// After 10 seconds, we quit the loop.
if ($elapsedTime > 10) {
$client->interrupt();
}
}
);
// Send the request. We use QoS 1 to have guaranteed delivery.
$mqtt->publish($publishTopic, $request, MqttClient::QOS_AT_LEAST_ONCE);
// Wait for a response. This will either return when we receive
// a response on the subscribed topic, or after 10 seconds
// due to our registered loop event handler.
$mqtt->loop();
// Always disconnect gracefully.
$mqtt->disconnect();
} catch (MqttClientException $e) {
\Log::error("Pinging device failed.", [
'device' => $device->id,
'exception' => $e->getMessage(),
]);
}
}
I have a function to send email to customer for every new registration. and my client want to record any unsuccessfull email sent (i.e if email address is wrong).
i try using try-cacth and mail::failure.
try{
Mail::send('mail.mail', compact(''), function ($message) use ($) {
$message->from();
$message->subject();
$message->to();
});
}
catch(\Swift_TransportException $e){
}
mail:failures
if (Mail::failures()) {
echo ('error');
}
but this working if network failure, such as email host is down. how to record/get info if email wasnt delivered because email address/domain not found.
i get this info in email if email wasnt delivered. but how to record it the ddetails into database.
Address not found
Your message wasn't delivered to asna#asmas.cl because the domain asmas.cl couldn't be found. Check for typos or unnecessary spaces and try again.
look my below code gets a json resposnse after sending an sms, your system should also get a response json after sending the email. The json carrys a set of data. check the particular data response you wish for and update it accordingly on your table.
$responseJson = json_decode($response, true);
// data returned --> [{"status":"200","response":"success","message_id":82682342,"recipient":"4113122"}]
$status = ($responseJson[0])['status'];
$responseDescripition = ($responseJson[0])['response'];
Log::info('API status >>>>> ' . $status);
Log::info('API Response Description >>>>> ' . $responseDescripition);
if (($responseJson[0])) {
DB::table('mess')->where('id', $request->input('template'))
->update([
'sentstatus' => '1',
'status' => $status,
'responsecode' => $responseDescripition,
'sent_on' => \Carbon\Carbon::now(),
]);
}
Our code sends twilio sms messages by doing the following:
// send the text message to the member's mobile phone
try {
// attempt to send the message through Twilio
$tw_msg = $twilio_client->messages->create(
"+1".$recipient['address'],
array (
'From' => "+1".$org['twilio_number'],
'Body' => $txtmsg,
'StatusCallback' => CALLBACK_LINK.'/text_message_handler.php'
)
);
// else trap the error since the message could not be sent and the callback routine is not called
} catch (Exception $e) {
// process the text message error
process_text_msg_error($db, $e, $org, $msg, $recipient);
}
In the v4 library we would get the error code by doing the following:
// get the twilio error components
$twilio_error_status = $e->getStatus();
$twilio_error_code = $e->getCode();
$twilio_error_msg = $e->getMessage();
This is not giving us what we expected using the V5 library. How do we get the error status and code using the V5 lib?
Twilio developer evangelist here.
It looks to me like you need to update one of the methods you call on the exception to get the status code. The exception is now a RestException and has the method getStatusCode(). You should update to:
// get the twilio error components
$twilio_error_status = $e->getStatusCode();
$twilio_error_code = $e->getCode();
$twilio_error_msg = $e->getMessage();
Let me know if that helps at all.
I have a function in my controller which saves messages from users, first it saves message into database than it sends email to that user's mail address and than it returns json response to the sender.
Problem: sometimes it takes too long for email to be sent, and the sender has to wait long time for the response, or sometimes email is not even sent (due to some smpt problems etc.) and it triggers an error, however I don't really care that much if email is sent or not, most important that message is saved to the database.
What I'm trying to achieve:
I want to save message to the database, ->
immediately after that send response to the sender, ->
and only after run Mail::send();
so run Mail::send() after controller returns json to the sender, so the sender will receive a positive response regardless of how Mail::send() performs
$message = new MessageDB;
$message->listing_id = e(Input::get('listing_id'));
$message->user_id = $listing->User->id;
$message->name = e(Input::get('name'));
$message->mobile = e(Input::get('mobile'));
$message->message = e(Input::get('message'));
if ($message->save()) {
Mail::send('emails.message', ['user' => 'Jon Doe','message' => $message], function($m) use($listing){
$listing_agent = $listing->Agent;
if ($listing->agent == null) {
$mail_to = $listing->User->email;
$name = '';
}else{
$mail_to = $listing->Agent->email;
$name = $listing->Agent->first_name.' '.$listing->Agent->second_name;
}
$m->to($mail_to)->subject('new message from company.com');
});
return ['success' => 1, 'message' => 'messasge has been sent'];
You can use Mail Queueing functions of Laravel. Here's the Link
Mail::queue('emails.welcome', $data, function($message) {});Queue mail for background Sending.
Mail::later(5, 'emails.welcome', $data, function($message){});Define Seconds after which mail will be sent.