line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
use strict; |
2
|
4
|
|
|
4
|
|
2084390
|
use warnings; |
|
4
|
|
|
|
|
36
|
|
|
4
|
|
|
|
|
117
|
|
3
|
4
|
|
|
4
|
|
24
|
use URI; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
2004
|
|
4
|
4
|
|
|
4
|
|
2093
|
use JSON::XS qw{decode_json}; |
|
4
|
|
|
|
|
24711
|
|
|
4
|
|
|
|
|
133
|
|
5
|
4
|
|
|
4
|
|
2862
|
use base qw{SMS::Send::Driver::WebService}; |
|
4
|
|
|
|
|
20345
|
|
|
4
|
|
|
|
|
256
|
|
6
|
4
|
|
|
4
|
|
29
|
|
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
2022
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.06'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 NAME |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
SMS::Send::NANP::Twilio - SMS::Send driver for Twilio |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 SYNOPSIS |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Configure /etc/SMS-Send.ini |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
[NANP::Twilio] |
18
|
|
|
|
|
|
|
AccountSid=AccountSid |
19
|
|
|
|
|
|
|
AuthToken=AuthToken |
20
|
|
|
|
|
|
|
MessagingServiceSid=String |
21
|
|
|
|
|
|
|
;From=+12025550123 |
22
|
|
|
|
|
|
|
;StatusCallback=URL |
23
|
|
|
|
|
|
|
;ApplicationSid=String |
24
|
|
|
|
|
|
|
;MaxPrice=USD |
25
|
|
|
|
|
|
|
;ProvideFeedback=true|false |
26
|
|
|
|
|
|
|
;ValidityPeriod=14400 |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
use SMS::Send; |
29
|
|
|
|
|
|
|
my $sms = SMS::Send->new('NANP::Twilio'); |
30
|
|
|
|
|
|
|
my $success = $sms->send_sms(text=> 'Hello World!', to =>'+17035550123'); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
use SMS::Send::NANP::Twilio; |
33
|
|
|
|
|
|
|
my $sms = SMS::Send::NANP::Twilio->new; |
34
|
|
|
|
|
|
|
my $success = $sms->send_sms(text=> 'Hello World!', to =>'+17035550123'); |
35
|
|
|
|
|
|
|
my $json = $sms->{__content}; |
36
|
|
|
|
|
|
|
my $href = $sms->{__data}; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 DESCRIPTION |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
SMS::Send driver for Twilio |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head1 METHODS |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head2 send_sms |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
Sends SMS Message via Twilio web service and returns 1 or 0. Method dies on critical error. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
my $status = $sms->send_sms(to =>'+17035550123', text=> 'Hello World!'); |
49
|
|
|
|
|
|
|
my $status = $sms->send_sms(to =>'+17035550123', text=> 'Image Attached', MediaUrl=>'https://...'); |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=over |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=item to |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
Passed as "To" in the posted form data. The destination phone number for SMS/MMS or a Channel user address for other 3rd party channels. Destination phone numbers should be formatted with a '+' and country code e.g., +16175550123 (E.164 format). |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
to => "+17035550123" |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=item text |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Passed as "Body" in the posted form data. The text of the message you want to send, limited to 1600 characters. |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
text => "My Message Body" |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=item MediaUrl |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
The URL of the media you wish to send out with the message. gif, png, and jpeg content is currently supported and will be formatted correctly on the recipient's device. Other types are also accepted by the API. The media size limit is 5MB. If you wish to send more than one image in the message body, please provide multiple MediaUrls values in an array reference. You may include up to 10 MediaUrls per message. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
MediaUrl => "https://...." |
70
|
|
|
|
|
|
|
MediaUrl => [$url1, $url2, ...] |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=back |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=cut |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
my $self = shift; |
77
|
|
|
|
|
|
|
my %argv = @_; |
78
|
0
|
|
|
0
|
1
|
0
|
|
79
|
0
|
|
|
|
|
0
|
my $to = $argv{'to'} or die('Error: to propoerty required'); |
80
|
|
|
|
|
|
|
my $text = defined($argv{'text'}) ? $argv{'text'} : ''; |
81
|
0
|
0
|
|
|
|
0
|
my @form = (To => $to, Body => $text); |
82
|
0
|
0
|
|
|
|
0
|
|
83
|
0
|
|
|
|
|
0
|
my $MediaUrl = $argv{'MediaUrl'} || []; |
84
|
|
|
|
|
|
|
$MediaUrl = [$MediaUrl] unless ref($MediaUrl) eq 'ARRAY'; |
85
|
0
|
|
0
|
|
|
0
|
die('Error: MediaUrl - You may include up to 10 MediaUrls per message.') if @$MediaUrl > 10; |
86
|
0
|
0
|
|
|
|
0
|
push @form, MediaUrl => $_ foreach @$MediaUrl; |
87
|
0
|
0
|
|
|
|
0
|
|
88
|
0
|
|
|
|
|
0
|
my $status_response; |
89
|
|
|
|
|
|
|
if ($self->From) { |
90
|
0
|
|
|
|
|
0
|
push @form, From => $self->From; |
91
|
0
|
0
|
|
|
|
0
|
$status_response = 'queued'; #When you only specify the From parameter, Twilio will validate the phone |
92
|
0
|
|
|
|
|
0
|
#numbers synchronously and return either a queued status or an error. |
93
|
0
|
|
|
|
|
0
|
} |
94
|
|
|
|
|
|
|
if ($self->MessagingServiceSid) { |
95
|
|
|
|
|
|
|
push @form, MessagingServiceSid => $self->MessagingServiceSid; |
96
|
0
|
0
|
|
|
|
0
|
$status_response = 'accepted'; #When specifying the MessagingServiceSid parameter, Twilio will first |
97
|
0
|
|
|
|
|
0
|
#return an accepted status. |
98
|
0
|
|
|
|
|
0
|
} |
99
|
|
|
|
|
|
|
die('Error: Property "From" or "MessagingServiceSid" must be configured.') unless $status_response; |
100
|
|
|
|
|
|
|
|
101
|
0
|
0
|
|
|
|
0
|
push @form, StatusCallback => $self->StatusCallback if $self->StatusCallback; |
102
|
|
|
|
|
|
|
push @form, ApplicationSid => $self->ApplicationSid if $self->ApplicationSid; |
103
|
0
|
0
|
|
|
|
0
|
push @form, MaxPrice => $self->MaxPrice if $self->MaxPrice; |
104
|
0
|
0
|
|
|
|
0
|
push @form, ProvideFeedback => $self->ProvideFeedback if $self->ProvideFeedback; |
105
|
0
|
0
|
|
|
|
0
|
push @form, ValidityPeriod => $self->ValidityPeriod if $self->ValidityPeriod; |
106
|
0
|
0
|
|
|
|
0
|
|
107
|
0
|
0
|
|
|
|
0
|
my $response = $self->uat->post_form($self->_url, \@form); #isa HASH from HTTP::Tiny |
108
|
|
|
|
|
|
|
die(sprintf('HTTP Error: %s %s', $response->{'status'}, $response->{'reason'})) unless $response->{'success'}; |
109
|
0
|
|
|
|
|
0
|
$self->{'__content'} = $response->{'content'}; |
110
|
0
|
0
|
|
|
|
0
|
my $data = decode_json($response->{'content'}); |
111
|
0
|
|
|
|
|
0
|
$self->{'__data'} = $data; |
112
|
0
|
|
|
|
|
0
|
return $data->{'status'} eq $status_response ? 1 : 0; |
113
|
0
|
|
|
|
|
0
|
} |
114
|
0
|
0
|
|
|
|
0
|
|
115
|
|
|
|
|
|
|
my $self = shift; |
116
|
|
|
|
|
|
|
my $url = URI->new(join '/', $self->url, 'Accounts', $self->AccountSid, 'Messages.json'); |
117
|
|
|
|
|
|
|
$url->userinfo(join ':', $self->AccountSid, $self->AuthToken); |
118
|
0
|
|
|
0
|
|
0
|
return $url; |
119
|
0
|
|
|
|
|
0
|
} |
120
|
0
|
|
|
|
|
0
|
|
121
|
0
|
|
|
|
|
0
|
=head1 PROPERTIES |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
Properties may be stored in Current Directory, /etc/SMS-Send.ini or C:\Windows\SMS-Send.ini. See L<SMS::Send::Driver::WebService>->cfg_path |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head2 url |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Returns the url for the Twilio versioned service. |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
Default: https://api.twilio.com/2010-04-01 |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=cut |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
#see SMS::Send::Driver::WebService->url |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head2 AccountSid |
137
|
|
|
|
|
|
|
|
138
|
0
|
|
|
0
|
|
0
|
The "AccountSID" is passed on the URL and sent as the username for basic authentication credentials |
139
|
0
|
|
|
0
|
|
0
|
|
140
|
0
|
|
|
0
|
|
0
|
=cut |
141
|
0
|
|
|
0
|
|
0
|
|
142
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
143
|
|
|
|
|
|
|
$self->{'AccountSid'} = shift if @_; |
144
|
|
|
|
|
|
|
unless (defined $self->{'AccountSid'}) { |
145
|
|
|
|
|
|
|
$self->{'AccountSid'} = $self->cfg_property('AccountSid', $self->_AccountSid_default) |
146
|
|
|
|
|
|
|
|| $self->cfg_property('username', $self->_username_default); #pre 0.04 |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
die('Error: AccountSid property required') unless defined $self->{'AccountSid'}; |
149
|
|
|
|
|
|
|
return $self->{'AccountSid'}; |
150
|
|
|
|
|
|
|
} |
151
|
1
|
|
|
1
|
1
|
4723
|
|
152
|
1
|
50
|
|
|
|
6
|
|
153
|
1
|
50
|
|
|
|
4
|
=head2 AuthToken |
154
|
0
|
|
0
|
|
|
0
|
|
155
|
|
|
|
|
|
|
The "AuthToken" sent as password for basic authentication credentials |
156
|
|
|
|
|
|
|
|
157
|
1
|
50
|
|
|
|
4
|
=cut |
158
|
1
|
|
|
|
|
5
|
|
159
|
|
|
|
|
|
|
my $self = shift; |
160
|
|
|
|
|
|
|
$self->{'AuthToken'} = shift if @_; |
161
|
0
|
|
|
0
|
|
0
|
unless (defined $self->{'AuthToken'}) { |
162
|
|
|
|
|
|
|
$self->{'AuthToken'} = $self->cfg_property('AuthToken', $self->_AuthToken_default) |
163
|
|
|
|
|
|
|
|| $self->cfg_property('password', $self->_password_default); #pre 0.04 |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
die('Error: AuthToken property required') unless defined $self->{'AuthToken'}; |
166
|
|
|
|
|
|
|
return $self->{'AuthToken'}; |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
170
|
1
|
|
|
1
|
1
|
3
|
=head2 From |
171
|
1
|
50
|
|
|
|
5
|
|
172
|
1
|
50
|
|
|
|
5
|
The "From" parameter passed in the posted form |
173
|
0
|
|
0
|
|
|
0
|
|
174
|
|
|
|
|
|
|
A Twilio phone number (in E.164 format), alphanumeric sender ID or a Channel Endpoint address enabled for the type of message you wish to send. Phone numbers or short codes purchased from Twilio work here. You cannot (for example) spoof messages from your own cell phone number. |
175
|
|
|
|
|
|
|
|
176
|
1
|
50
|
|
|
|
3
|
=cut |
177
|
1
|
|
|
|
|
4
|
|
178
|
|
|
|
|
|
|
my $self=shift; |
179
|
|
|
|
|
|
|
$self->{'From'}=shift if @_; |
180
|
0
|
|
|
0
|
|
0
|
$self->{'From'}=$self->cfg_property('From', $self->_From_default) unless defined $self->{'From'}; |
181
|
|
|
|
|
|
|
return $self->{'From'}; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=head2 MessagingServiceSid |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
The "MessagingServiceSid" parameter passed in the posted form |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
The 34 character unique id of the Messaging Service you want to associate with this Message. Set this parameter to use the Messaging Service Settings and Copilot Features you have configured. When only this parameter is set, Twilio will use your enabled Copilot Features to select the from phone number for delivery. |
190
|
|
|
|
|
|
|
|
191
|
1
|
|
|
1
|
1
|
3
|
=cut |
192
|
1
|
50
|
|
|
|
4
|
|
193
|
1
|
50
|
|
|
|
4
|
my $self=shift; |
194
|
1
|
|
|
|
|
5
|
$self->{'MessagingServiceSid'}=shift if @_; |
195
|
|
|
|
|
|
|
$self->{'MessagingServiceSid'}=$self->cfg_property('MessagingServiceSid', $self->_MessagingServiceSid_default) unless defined $self->{'MessagingServiceSid'}; |
196
|
|
|
|
|
|
|
return $self->{'MessagingServiceSid'}; |
197
|
0
|
|
|
0
|
|
0
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head2 StatusCallback |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
The "StatusCallback" parameter passed in the posted form |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
A URL where Twilio will POST each time your message status changes to one of the following: queued, failed, sent, delivered, or undelivered. Twilio will POST the MessageSid along with the other standard request parameters as well as MessageStatus and ErrorCode. If this parameter passed in addition to a MessagingServiceSid, Twilio will override the Status Callback URL of the Messaging Service. URLs must contain a valid hostname (underscores are not allowed). |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=cut |
207
|
|
|
|
|
|
|
|
208
|
1
|
|
|
1
|
1
|
5
|
my $self=shift; |
209
|
1
|
50
|
|
|
|
5
|
$self->{'StatusCallback'}=shift if @_; |
210
|
1
|
50
|
|
|
|
5
|
$self->{'StatusCallback'}=$self->cfg_property('StatusCallback', $self->_StatusCallback_default) unless defined $self->{'StatusCallback'}; |
211
|
1
|
|
|
|
|
6
|
return $self->{'StatusCallback'}; |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
0
|
|
|
0
|
|
|
|
215
|
|
|
|
|
|
|
=head2 ApplicationSid |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
The "ApplicationSid" parameter passed in the posted form |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Twilio will POST MessageSid as well as MessageStatus=sent or MessageStatus=failed to the URL in the MessageStatusCallback property of this Application. If the StatusCallback parameter above is also passed, the Application's MessageStatusCallback parameter will take precedence. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=cut |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
my $self=shift; |
224
|
|
|
|
|
|
|
$self->{'ApplicationSid'}=shift if @_; |
225
|
0
|
|
|
0
|
1
|
|
$self->{'ApplicationSid'}=$self->cfg_property('ApplicationSid', $self->_ApplicationSid_default) unless defined $self->{'ApplicationSid'}; |
226
|
0
|
0
|
|
|
|
|
return $self->{'ApplicationSid'}; |
227
|
0
|
0
|
|
|
|
|
} |
228
|
0
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=head2 MaxPrice |
231
|
0
|
|
|
0
|
|
|
|
232
|
|
|
|
|
|
|
The "MaxPrice" parameter passed in the posted form |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
The total maximum price up to the fourth decimal (0.0001) in US dollars acceptable for the message to be delivered. All messages regardless of the price point will be queued for delivery. A POST request will later be made to your Status Callback URL with a status change of "Sent" or "Failed". When the price of the message is above this value the message will fail and not be sent. When MaxPrice is not set, all prices for the message is accepted. |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=cut |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
my $self=shift; |
239
|
|
|
|
|
|
|
$self->{'MaxPrice'}=shift if @_; |
240
|
|
|
|
|
|
|
$self->{'MaxPrice'}=$self->cfg_property('MaxPrice', $self->_MaxPrice_default) unless defined $self->{'MaxPrice'}; |
241
|
|
|
|
|
|
|
return $self->{'MaxPrice'}; |
242
|
0
|
|
|
0
|
1
|
|
} |
243
|
0
|
0
|
|
|
|
|
|
244
|
0
|
0
|
|
|
|
|
|
245
|
0
|
|
|
|
|
|
=head2 ProvideFeedback |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
The "ProvideFeedback" parameter passed in the posted form |
248
|
0
|
|
|
0
|
|
|
|
249
|
|
|
|
|
|
|
Set this value to true if you are sending messages that have a trackable user action and you intend to confirm delivery of the message using the Message Feedback API. This parameter is set to false by default. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=cut |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
my $self=shift; |
254
|
|
|
|
|
|
|
$self->{'ProvideFeedback'}=shift if @_; |
255
|
|
|
|
|
|
|
$self->{'ProvideFeedback'}=$self->cfg_property('ProvideFeedback', $self->_ProvideFeedback_default) unless defined $self->{'ProvideFeedback'}; |
256
|
|
|
|
|
|
|
return $self->{'ProvideFeedback'}; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
0
|
|
|
0
|
1
|
|
|
260
|
0
|
0
|
|
|
|
|
=head2 ValidityPeriod |
261
|
0
|
0
|
|
|
|
|
|
262
|
0
|
|
|
|
|
|
The "ValidityPeriod" parameter passed in the posted form |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
The number of seconds that the message can remain in a Twilio queue. After exceeding this time limit, the message will fail and a POST request will later be made to your Status Callback URL. Valid values are between 1 and 14400 seconds (the default). Please note that Twilio cannot guarantee that a message will not be queued by the carrier after they accept the message. We do not recommend setting validity periods of less than 5 seconds. |
265
|
0
|
|
|
0
|
|
|
|
266
|
|
|
|
|
|
|
=cut |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
my $self=shift; |
269
|
|
|
|
|
|
|
$self->{'ValidityPeriod'}=shift if @_; |
270
|
|
|
|
|
|
|
$self->{'ValidityPeriod'}=$self->cfg_property('ValidityPeriod', $self->_ValidityPeriod_default) unless defined $self->{'ValidityPeriod'}; |
271
|
|
|
|
|
|
|
return $self->{'ValidityPeriod'}; |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=head1 SEE ALSO |
276
|
0
|
|
|
0
|
1
|
|
|
277
|
0
|
0
|
|
|
|
|
L<SMS::Send::Driver::WebService>, L<SMS::Send>, L<https://www.twilio.com/docs/api/messaging/send-messages> |
278
|
0
|
0
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
=head1 AUTHOR |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
Michael R. Davis |
282
|
0
|
|
|
0
|
|
|
|
283
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
MIT License |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Copyright (c) 2022 Michael R. Davis |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=cut |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
1; |