File Coverage

blib/lib/SMS/Send/NANP/Twilio.pm
Criterion Covered Total %
statement 33 101 32.6
branch 10 68 14.7
condition 0 8 0.0
subroutine 9 30 30.0
pod 10 10 100.0
total 62 217 28.5


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;