Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Curl usage with Perl's system command

by perlron (Pilgrim)
on Oct 28, 2014 at 14:31 UTC ( [id://1105323]=perlquestion: print w/replies, xml ) Need Help??

perlron has asked for the wisdom of the Perl Monks concerning the following question:


A popular mail blasting service does not have a perl api, but thankfully has a curl one i can use :D
My difficulty is in composing the multiline format string that will constitute the mail message.
Ive put together the code and it works as such, but unfortunately one area i am still not getting is adding multiple lines to the message in a clean and efficient manner. The system command usage is not working with me when i try to passing strings to it as an array argument?
how can i debug / solve this ?
I even tried shell quotes as a monk corrected earlier here, but i still dont get the hang of what is going wrong .
#!/usr/bin/perl use Capture::Tiny qw/ capture /; use String::ShellQuote; my ($stdout,$stderr,$exit) = capture { my $command = " curl -s --user \'api:key*****\'"; $command .= " https://api.****/**/*****/messages"; $command .= " -F from='*****'"; $command .= " -F to=\'Name <$to_id>\'"; $command .= " -F subject=\'$subject\'"; $command .= " -F text=\'$message\'"; my $message = " -F text=\'test a new line\'"; @args = ($message); #this works system $command ; #this doesnt. result is -1 system $command @args; #this doesnt either. result is -1 system $command shell_quote @args }; print $stdout,$stderr,$exit;
Do not wait to strike when the iron is hot! Make it hot by striking - WB Yeats

Replies are listed 'Best First'.
Re: Curl usage with Perl's system command
by Loops (Curate) on Oct 28, 2014 at 14:53 UTC

    Hey there

    You need to build up the parameter array manually, with each individual element, not all in one string. This way system will call curl directly, and not via the shell where the quoting gets complicated:

    use strict; use warnings; use Capture::Tiny qw/ capture /; my ($to_id, $subject, $message) = qw(AA BB CC); my @args = ( '-v', '-s', '--user', 'api:key*****', '-F', "from=*****", '-F', "to=Name <$to_id>", '-F', "subject=$subject", '-F', "text=$message", 'https://api.****/**/*****/messages', ); my ($stdout,$stderr,$exit) = capture { system 'curl', @args; }; print $stdout,$stderr,$exit;

    Added -v to the options so that you can see what is going on, although you wont want that once you get things sorted out. Another option is WWW::Curl on CPAN which has a Perl API overtop of Curl.

      ok..will def try this out. this is what the other monk in the CRLF post i mentioned was trying to say, somehow i didnt grasp it. thanks
      Do not wait to strike when the iron is hot! Make it hot by striking - WB Yeats
      partial success. Its difficult to correct errors inside strings.

      https://api.****/**/*****/messages has to be quoted with '\' and so does api:key***** without which i get a HTTP 400 bad request. found this by checking the original curl string from the company.
      when i use it with '' eg '\'api:key-123456etc1234\'' and '\'https://api.****/**/*****/messages\''
      i get this message which seems quite documented on stack overflow
      Protocol 'https not supported or disabled in libcurl
      same for http as well.strange
      Protocol 'http not supported or disabled in libcurl
      i will try this on the server, maybe it might just work there.
      1st update curl-config --protocols shows me that HTTP is supported on my m/c.
      so i guess im still in the woods with quoting things in perl :D. thanks for the help sir.
      ill find a way out.
      2nd update. thanks its working for me. well its just a string thing i goofed up somewhere as revealed in libcurl documentation.ive changed the order of the URL around. For all practical purposes your code was spot on. The only thing i faced is the to name<name@email> for sender address was not being accepted and i actually passed a string there.
      But this is just a start. I guess LWP or WWW::Curl will be the right approach i understand.thanks!
      for funssake im putting up the working code here. But Loops code is 99.99%% accurate for my use i would say. I hope such situatiosn never arise where i need to take someone elses code :D. Thanks
      use strict; use warnings; use Capture::Tiny qw/ capture /; my $message = "first line of text"; $message .= "\nsecond line of text"; my ($to_id, $subject) = qw(ron\@asdfasdf.cc testMessage); my @args = ( '-v', '-s', '--user',"api:key-123456", , 'https://api.XXX.net/v2/xxx.yyy.org/messages', ,'-F', "from='xxx yyy <postmaster\@xxx.yyy.org>", ,'-F', "to=ron\@xxx.cc", ,'-F', "subject=\'$subject\'", ,'-F', "text=\'$message\'"); my ($stdout,$stderr,$exit) = capture { system 'curl', @args; };
Re: Curl usage with Perl's system command
by hippo (Bishop) on Oct 28, 2014 at 14:49 UTC

    The correct call to system would be:

    system ($command, @args);

    However, I don't see any advantage to forking out to curl when you could be using LWP or similar. Do you have a particular reason for that?

      no i tried that it with brackets it doesnt seem to work.
      Its definitely a curl command quirk that im missing as using system with shell commands like ls work fine with and without args.
      Ok LWP , i hadnt thought yet of using. The curl API was available on the server so it was a quick copy paste and use for me.
      are you recommending i try LWP as an alternative to using curl ? and just use the same URLS and strings the mail company is giving me ??
      im not an expert in perl, but that i think would be interesting.
      on a lighter note.i can even post it to that mail company and tell them to support perl!
      Do not wait to strike when the iron is hot! Make it hot by striking - WB Yeats
        are you recommending i try LWP as an alternative to using curl ?

        Absolutely! LWP (or a similar module) keeps everything within perl. This means that there's no comparable overhead (no shell or sub-process to be created) and that the response can be examined easily and in detail instead of just getting the integer return code from system(). It also gives you a cookie jar, control over SSL options (where applicable) and all manner of other goodies. Definitely give it a try.

Re: Curl usage with Perl's system command
by Your Mother (Archbishop) on Oct 28, 2014 at 16:48 UTC

    Follow-up on some other remarks and clear up a misunderstanding. There is no such thing as a "curl API" to a webservice. This is a web/HTTP API and curl is just one of innumerable tools that can be used as an HTTP client to interact with that particular service's API.

    HTTP is programming language agnostic. Perl, Python, Java, Ruby, C, is irrelevant. Shelling out from a program is harder than using packages like WWW::Mechanize. Though in this case since you're doing cut and paste programming, the curl advice you've been getting might be easier than starting over the "right" way.

      what i meant as a curl option was a way to code only using perl. i prefer to use perl as the only programming language in my startup. if there is a beter way please let me know. right now i think LWP or the WWW::Curl option seem a good thing for a better approach.
      Do not wait to strike when the iron is hot! Make it hot by striking - WB Yeats
Re: Curl usage with Perl's system command
by Your Mother (Archbishop) on Oct 28, 2014 at 18:26 UTC

    This worked fine, WWW::Mechanize, LWP::UserAgent, and JSON to handle the messages from the API. You will have to put in your own valid ids etc. The ones below are randomized/edited.

    use strictures; use WWW::Mechanize; my $mech = WWW::Mechanize->new(); $mech->credentials( api => "key-da0f99505ece11e48064d6516832a126" ); $mech->post( "https://api.mailgun.net/v2/xyz.mailgun.org/messages", [ from => 'Mailgun Sandbox <postmaster@sandboxyz.mailgun. +org>', to => 'Kitty <fluffy@cats.co.uk.jp.org>', subject => 'OHAI', text => 'Congratulations! You are a winner. A loser no +more!!' ]); print $mech->response->as_string, $/;
    { "message": "Queued. Thank you.", "id": "<20141028181741.33218.21053@sandboxyz.mailgun.org>" }

    First principles, I really recommend against cut and paste programming. You have to know what everything does or you might do something dangerous and you will certainly waste time treating each script as a mystical invocation.

    I also think you should have included the real service and such in your original question to make it easier. Not that it was hard to find but if you want help, lowering the bar to do so is often the difference between an answer in 30 minutes and an answer never.

      thanks ill check this. quite kind of you.
      i thought it would be against the rules n such to post company info.
      Do not wait to strike when the iron is hot! Make it hot by striking - WB Yeats

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1105323]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2024-04-23 15:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found