Alternative ways to send email without UI from ipad or iphone - ios

I see there are many ways to send email in the background (without UI) in iOS devices and without using MFMailComposeViewController class. Most popular examples are fill an online form and press submit button. Here are the most popular methods i see in stackoverflow..
(1) Using your own SMTP client. This approach is working for me but in my private network but not working in my company premises as in company network I am not allowed to use gmail (public emails) and don't have SMTP details of our company mail server. I am struck here in this approach.
(2) Using CTCoreMessage & Three20 Framework (open source). But here I am not able to find where to download this framework other than git, where my pc VLAN not allowing GIT. Could somebody help me to find out the Three20 Framework downloadable location and share me an example code.
(3) Using HTTP Post: Send your email body to the server and delegate the email sending to the HTTP Server. If this is simple then can somebody help me how to setup your own HTTP Server for sending emails.
Could anybody help in finding any working sample code. I am at end of my project delivery. Posted this long back. No replies till now. Could anybody help me please..

I would look into using Mailgun, it will make sending emails much easier and handles up to 10k a month for free. They allow you to use their subdomain if you dont have your own, but can easily setup your own to work with theirs.
Its as easy as installing up a cocoapod and adding 5 lines of code or so.

I might be able to provide some help for the third option, using HTTP Post, since I did implement it once in a project.
First, I used this nice and simple iOS class to take care of the posting for me.
Then, the following iOS code snippet should show you how it's done
NSString* from = #"sender#email";
NSString* to = #"receiver#email";
NSString* mailCc = #"cc#email";
NSString* message = #"my message"
NSString* subject = #"my subject";
NSURL* url = [NSURL URLWithString:#"http://yourtestsite.com/my_email_script.php"];
//these are $_POST variables sent, so 'from' would be $_POST['from']
NSArray *keys = [[NSArray alloc] initWithObjects:#"from", #"to", #"cc", #"subject", #"message", nil];
NSArray *objects = [[NSArray alloc] initWithObjects:from, to, mailCc, subject, message, nil];
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
NSMutableURLRequest* request = [SimplePost urlencodedRequestWithURL:url andDataDictionary:dictionary];
NSURLResponse* response = [[NSURLResponse alloc] init];
NSError* error = [[NSError alloc] init];
NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
NSString* result = [[NSString alloc] initWithData:returnData encoding:NSStringEncodingConversionAllowLossy];
//I'm checking for 1 because my php script was set to write 1 to the page in case of success and 0 otherwise, so this is simply my implementation
if([result isEqualToString:#"1"]) {
NSLog(#"success");
} else {
NSLog(#"error");
}
For the PHP file, this should do the trick
$from = filter_var($_POST['from'], FILTER_SANITIZE_EMAIL);
$to = filter_var($_POST['to'], FILTER_SANITIZE_EMAIL);
$cc = filter_var($_POST['cc'], FILTER_SANITIZE_EMAIL);
$subject = htmlspecialchars(utf8_decode($_POST['subject']));
$message = utf8_decode($_POST['message']);
// To send HTML mail, the Content-type header must be set
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
// Additional headers
$headers .= 'From: ' . $from . "\r\n";
$headers .= 'Cc: ' . $cc . "\r\n";
// Mail it
if(mail($to, $subject, $message, $headers)) {
echo("1");
} else {
echo("0");
}
Keep in mind, I'm no PHP expert, so that code might be improved, especially on the security part.
[edit]
PHP mailing should already be enabled in most major managed hosting solutions, be it a cheap shared account, a VPS or a dedicated server. But if you plan to send A LOT of emails with this method, then a dedicated server is recommended.
However, there is a limit of emails you can send and better options than the mail function. You can find more info about this here.
[later edit]
It seems the author deleted the SimplePost class. However, the same author made an alternative which should help, called SimpleHTTPRequest. The rest should remain the same

Related

How can I receive update status(data) when I request ride with UBSDKRideRequestViewController (Uber SDK)

I have added Uber SDK in my application. I didn't request project to Request full access. It's on development. and I have issues that I can't find an answer (I'm using sandbox mode.)
Q. I need to test. If I requested and driver is already accepted. How can I know the time that he will arrive or other status e.g.arrived . and How can I send notification to my user in my application when driver is arrived. I see UBSDKRideRequestViewControllerDelegate response only error case.
this's my code.
UBSDKRideParametersBuilder *builder = [[UBSDKRideParametersBuilder alloc] init];
[builder setPickupToCurrentLocation];
[builder setDropoffLocation:dropoffLocation];
UBSDKRideParameters *parameters = [builder build];
NSArray<UBSDKRidesScope *> *scopes = #[UBSDKRidesScope.RideWidgets,UBSDKRidesScope.Profile,UBSDKRidesScope.Request];
UBSDKLoginManager *loginManager = [[UBSDKLoginManager alloc] init];
UBSDKRideRequestViewController *vc = [[UBSDKRideRequestViewController alloc] initWithRideParameters:parameters loginManager:loginManager];
vc.title = #"Uber";
vc.delegate = self;
please advice thanks.
Currently, the Ride Request Widget does not provide you notifications for changes in trip status. You can, however, get the status of the current trip by using a RidesClient and calling fetchCurrentRide which will give you details about the current trip. In order to access trips from the widget on this endpoint, however, you will need the all_trips scope. This will require you to handle login separately from the RideRequestViewController. You can use the LoginButton or LoginManager to request the AllTrips and RideWidgets RidesScopes
In terms of testing, you can update the status of a sandbox trip by making a PUT request to the /v1/sandbox/requests/{request_id} endpoint with a JSON body in the form {"status": "accepted"} (replacing the status you want to see). This status change would then be reflected in your app. You can find more information on the sandbox on the Uber Developer Site

iOS dropbox sdk / core api - listing public folder contents without authorization

I've tried checking on stackoverflow and on the api docs, but couldn't find any info pertaining to this particular question.
What I'm trying to do is getting the public folder contents of a particular dropbox account (like the /metadata function of the api), without the need to authorize/link to dropbox.
I know "/metadata/link" allows you to get metadata of a particular link without user authorization, but I couldn't find a way to get regular metadata and file listing...
Actually it doesn't even need to be a public folder (as I've read recently that dropbox discourages developers regarding relying on public folders for apps), it can just as well be a regular folder through its shared link or anything of the kind...
I'm using api v1 (but can consider changing to v2 if this is impossible with v1), although I'm not even sure if this is at all possible.
Thank you!
For future reference, if anyone needs this as well, here's how I did it:
NSString *parameters = [NSString stringWithFormat:#"?link=%#&client_id=%#&client_secret=%#",fileUrl, appKey, appSecret];
NSString *sharedPath = [NSString stringWithFormat:#"%#/%#",#"https://api.dropbox.com/1/metadata/link", parameters];
NSURL *url = [NSURL URLWithString:sharedPath];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
theRequest.timeoutInterval = 5.0;
theRequest.HTTPMethod = #"POST";
NSData * resData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
Use NSJSONSerialization to parse resData and refer to the api documentation for json fields, and that's it.
For the sake of simplicity showing it here I used synchronous request, but it can just as easily be done with asynchronous connection delegates.

Use post request to receive LinkedIn user profile information in iOS

I am looking for a way to retrieve the profile information of a LinkedIn user by making a post request, I have read these two LinkedIn pages but it doesn't seem to explain much, or I couldn't understand much of it:
REST API LinkedIn
basic profile informations
I have seen these example on stackoverflow but I didn't understood to much:
http://api.linkedin.com/v1/people/~:(id,first-name,last-name,maiden-name,email-address,formatted-name,phonetic-last-name,location:(country:(code)),industry,distance,current-status,current-share,network,skills,phone-numbers,date-of-birth,main-address,positions:(title),educations:(school-name,field-of-study,start-date,end-date,degree,activities))
I am only interested to retrieve the skills section the one that on the website appears as so:
There's a fantastic library for LinkedIn-iOS integration by Kirsten Jones, you can use that to make calls to the LinkedIn API. You need an access token to make calls.
https://github.com/PrincessPolymath/LinkedIn-OAuth-Sample-Client
Make calls like this:
NSURL *url = [NSURL URLWithString:#"http://api.linkedin.com/v1/people/~:(id,first-name,last-name,maiden-name,formatted-name,phonetic-last-name,location:(country:(code)),industry,distance,current-status,current-share,network,skills,phone-numbers,date-of-birth,main-address,positions:(title),educations:(school-name,field-of-study,start-date,end-date,degree,activities))"]];
OAMutableURLRequest *request =
[[OAMutableURLRequest alloc] initWithURL:url
consumer:oAuthLoginView.consumer
token:oAuthLoginView.accessToken
callback:nil
signatureProvider:nil];
[request setValue:#"json" forHTTPHeaderField:#"x-li-format"];
OADataFetcher *fetcher = [[OADataFetcher alloc] init];
[fetcher fetchDataWithRequest:request
delegate:self
didFinishSelector:#selector(profileApiCallResult:didFinish:)
didFailSelector:#selector(profileApiCallResult:didFail:)];
- (void)profileApiCallResult:(OAServiceTicket *)ticket didFinish:(NSData *)data
{
NSString *responseBody = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSDictionary *profile = [responseBody objectFromJSONString];
if ( profile )
{
name.text = [[NSString alloc] initWithFormat:#"%# %#",
[profile objectForKey:#"firstName"], [profile objectForKey:#"lastName"]];
headline.text = [profile objectForKey:#"headline"];
.....and get skills and other user details
}
}
Use tool:https://apigee.com/console/linkedin
API to get the list of Skills:
https://api.linkedin.com/v1/people/~:(id,num-connections,skills)?format=json
I tried it in the Console tool and able to fetch the skills for my profile. I think the individual skill ID with above request should help you to get further information. Try it out.
If anyone is reading this answer, the LinkedIn API has limited access as of May 2015. You will need to apply to their Apply with LinkedIn program to access full profile fields including skills.
https://developer.linkedin.com/docs/fields
I have fair amount of experience working with the linkedIn API. It's been a little while, but hopefully this will set you on the right track.
To get profile information from a linked in user who is one of your connections you need a format like follows:
NSString *theRequest = [NSString stringWithFormat:#"https://api.linkedin.com/v1/people/id=abc123:(first-name,last-name,picture-url,location:(name))?oauth2_access_token=%#&format=json", accessToken];
This request will return the first name, last name, profile picture url, and location of the user with the id specified.
You can see a list of field types you can request by checking out linkedIn's documentation on their profile field descriptions here:
https://developer.linkedin.com/docs/fields
If you're wondering how to get the id of the user whose profile information you want request in the first place, you can make request for some basic info (including ids) of all your connections like this:
NSString *basicConnectionInfo = [NSString stringWithFormat:#"https://api.linkedin.com/v1/people/~/connections:(id,first-name,last-name)?oauth2_access_token=%#&format=json", accessToken];
This request will give you the id, first name, and last name of all of your connections. After you've gotten the id of the person you want, you can make a request using the user's id (as shown in the first example).
Now for the slightly unfortunately news... If you followed the link provided above, you'll notice that the skills field is part of the "Member profile fields available to Apply with LinkedIn developers". I'm assuming you'll have to follow this link they provided: https://developer.linkedin.com/docs/apply-with-linkedin in order to access the skills member profile field.
I have not applied with LinkedIn. So, I haven't tested a call to the skills field. But, I'm guessing it'll be similar to the examples I've shown you. Hope this helps!

How do I upload files to Google Cloud Storage in Objective-C/iOS?

I've been looking for documentation on how to upload files to my 'bucket' in Google Cloud Storage from my iOS app, but I can't find anything at all on the subject. No documentations, no tutorials, no example projects. Am I completely blind? I am simply trying to find a way for my app-users to upload a file to a "public bucket", and get a URL in return. All I can find is chunks of HTTP-protocols or JSON etc, and I have no idea how to use that, but there's no reference to it either. It feels like the author of those documentations expects me to know everything already. I've found some OSX-example codes, but they are too without documentation, and I've been trying to read the code they have provided, but with no luck.
What I'm looking for is something like this:
(This code is made up. It's what I want. I noticed Google used the prefix GTL* for their classes)
NSData *dataToUpload = ... ; //Or UIImage or some movie-format or whatever
NSURL *destination;
GTLStorageUploader *uploader = [GTLStorageUploader alloc]initWithBucket:#"myBucket" withHashOrKeyOrSomething:#"a1b2c3hashkeyOrWhatever"];
destination = [uploader uploadData:dataToUpload];//inBackground etc..
It's actually easier than this when using Parse.com, but there's simply not enough storage space for my app there, so I need to be able to upload the data files to Google Cloud Storage. How?
I did eventually get this to work. It wasn't pretty, though.
It's quite a long time ago now, so I can't really remember all the logic etc, but I'll post what made it work, and change the ID-stuff. I hope it helps, and sorry I didn't remember to write this when I found out and it was fresh in mind. I don't have time to get into this at the moment.
An important note: I also had to change a lot of permissions on the bucket and on the users/authorized on GoogleCloudStorage to make this work. We tried so many different combinations, but I THINK this was the stuff we did:
On each bucket: "Allow everyone to upload/delete/edit etc".
On the auth for the entire CloudStorage: "Allow only entities with certain accessToken to access this CloudStorage.
Allow only www.yourAppEngineURL.com to request such an accessToken.
This felt wrong, and still does. If anyone gets a hold of this accessToken, they can do whatever they want as long as that accessToken is valid. Like.. delete all files. But that was the only way we could make it work. Of course, only authorized users could request this accessToken from OUR appEngine, but still.. meh. I'm no security-guru, and this was just a fun project, so we let it go. Now to the code.
When uploading:
GTLServiceStorage *serv = [[GTLServiceStorage alloc] init];
serv.additionalHTTPHeaders = [NSDictionary dictionaryWithObjectsAndKeys:
#"123123123", #"x-goog-project-id",
#"application/json-rpc", #"Content-Type",
#"application/json-rpc", #"Accept", nil];
GTLStorageObjectAccessControl *objAccessControl = [GTLStorageObjectAccessControl new];
objAccessControl.entity = #"project-owners-123456"; //Some value from the control panel on CloudStorage or something. Or Apps.. Or AppEngine, not sure.
//Probably connected to the accessToken my AppEngine requests and sends to users.
objAccessControl.role = #"OWNER";
GTLStorageObjectAccessControl *objAccessControl2 = [GTLStorageObjectAccessControl new];
objAccessControl2.entity = #"allUsers";
objAccessControl2.role = #"READER";
//Don't remember why I need both. Or what they do. Hey ho.
//It looks like.. Everybody can read. Only my authorized accessToken-people can write? probably.
GTLStorageBucket *bucket = [[GTLStorageBucket alloc] init];
bucket.name = #"my_bucket";
NSError *err;
NSFileHandle *fileHandle = [NSFileHandle myLocalFileURLiThink error:&err];
if(err)
{
NSLog(#"Some error here");
}
GTLUploadParameters *params = [GTLUploadParameters uploadParametersWithFileHandle:fileHandle MIMEType:#"video/mp4 (or something else)"];
GTLStorageObject *storageObject = [[GTLStorageObject alloc] init];
storageObject.acl = #[objAccessControl, objAccessControl2];
NSString *key = [NSString stringWithFormat:#"fileName.mp4"];
// should probably be unique.. The url will be cloud.com/my_bucket/fileName.mp4
//You can generate something unique by putting together the user's userID and the timeStamp for the dateTime right now.
//This user will never upload two things within this second.
storageObject.name = key;
After this point in the code I do some magic I'm not gonna post. I ask for and receive an accessToken to use on GoogleCloudStorage from our own API.
I don't remember where or how I got that token to begin with, but I believe that the backend (AppEngine) had to request it from the CloudStorage-thing, using a pretty standard call.
And, as I said in the beginning, we changed some settings on CloudStorage making our AppEngine the only entity allowed to request this token. Or something.. This token has a lifecycle of like.. 15 minutes or so.. I don't know, it's provided by some Google-default-thing. I might look into it later if any of you need it.
NSString *receivedAccessToken = #"abc123"; //Received from CloudStorage via AppEngine.
NSString *accessToken = #"Bearer %#", receivedAccessToken" //(pseudo) Because it needed to say "Bearer " first. Don't know why, or how I found out..
[serv setAdditionalHTTPHeaders:[NSDictionary dictionaryWithObject:accessToken forKey:#"Authorization"]];
//Upload-magic:
GTLQueryStorage *query = [GTLQueryStorage queryForObjectsInsertWithObject:storageObject bucket:bucket.name uploadParameters:params];
GTLServiceTicket *t = [serv executeQuery:query completionHandler:^(GTLServiceTicket *ticket, id object, NSError *error) {
//Handle error first.
NSLog(#"Success!");
dispatch_async(dispatch_get_main_queue(), ^{
actualURL = [NSString stringWithFormat:#"%#%#", yourFullBucketURL /*( e.g www.googleCloud.com/my_bucket)*/, key /*file.mp4*/];
});
}];
And you can track the progress of the upload after this block, with the ticket-object (like, t.uploadProgressBlock = ...).
This code has been edited quite a bit for Stack-purposes now, so I might have screwed up something, so I probably doesn't work exactly like this. But read it, and try to understand how it works. Good luck. If you have the option, stay with Amazon or something else, this was not fun to work with. Worst documentation ever. Also, Amazon's S3 uploads/downloads faster than GoogleCloudStorage. I regret changing from Amazon to Google. Amazon had so much better API too, almost like the one in my question.
Here's the code used by AppEngine to request the AccessToken:
private GoogleCredential getGoogleCredential(String scope) throws GeneralSecurityException, IOException
{
JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(Constants.SERVICE_ACCOUNT_EMAIL)
.setServiceAccountPrivateKeyFromP12File(new File(Constants.CLOUD_STORAGE_KEY))
.setServiceAccountScopes(Collections.singleton(scope))
.build();
return credential;
}
The parameter "scope" sent in to this method is either https://www.googleapis.com/auth/devstorage.read_only or https://www.googleapis.com/auth/devstorage.read_write
The method returns a GoogleCredential-object, on which you can call googleCredential.refreshToken(). I believe this is the call made to get the token. I'm not sure though.
The Constants (email and key) are stuff you need to set up and get from the auth-page on Google Cloud Storage, I think.
This documentation should cover some of it (it looks more documented now than it did then, I think): https://cloud.google.com/storage/docs/authentication

Survey application with offline capabilities and how to capture the data from multiple ipads to one?

I am trying to build a Survey application where the surveys will be taken offline on multiple ipads and when these ipads are online they are going to upload the data(survey answers) to our servers? I am really struggling how to send the survey to multiple ipads and more importantly to capture from different ipads to one source ?
I need help to clear my architecture part and I need some examples to do the coding part. Do you know anything similar?
What are you ideas?
Many Thanks in advance,
Arda
Create a web server to accept and send survey questions and answers.
I would envision an app that goes like this:
1) Slave iPads makes a HTTP POST request to server asking for the survey
This is usually done using a networking library for iOS like MKNetworkKit or AFNetworking. The general process is to:
create a NSDictionary of key-value pairs to form the HTTP POST request
submit the data through a block construct with completion handler
So something like:
MKNetworkOperation *op = [engine operationWithURLString:#"http://www.mywebserver.com/api/fetchQuestions"
params:nil
httpMethod:#"POST"];
2) Server receives request, grabs all survey questions in database and return JSON encoded questions to slave ipads.
I'm not sure what platform your web server is on but in the past, I used Symfony 2.0 which is a PHP web framework.
It provides very helpful tools like Doctrine (an Object Relational Mapper or ORM) to let me work with my MySQL data as if they're programming objects.
So my general process for fetching data would be something like:
// pseudo php function codes
public function sendSurveyQuestionAction()
{
$repository = $this->getDoctrine()->getRepository('MyAppBundle:Survey');
$query = $repository->createQueryBuilder('query')->getQuery();
$arrObjs = $query->getResult();
$arrObjDatas = NULL;
foreach($arrObjs as $obj)
{
$arrObjDatas[] = $obj->toArray();
}
$response = new Response(json_encode(array('data' => $arrObjDatas)));
$response->headers->set('Content-Type', 'application/json');
$return $response;
}
This would return all survey in JSON format, ready to be parsed by your master iPad app.
3) Users on slave iPads fill in the questions through the app UI and submits. The app saves
the data to disk, checks for a working internet connection before sending data back to server.
Submitting the answer is very similar grabbing the questions, so your iOS code should be something like:
// ------------------------------------------------------------------------------------
// store all question-answers into a dictionary to be submitted as HTTP POST variables
// obviously, you wouldn't create it here, this is just example code, you would likely
// have stored your questions and answers when user presses 'finish' button
// ------------------------------------------------------------------------------------
NSMutableDictionary *paramDictionary = [[NSMutableDictionary alloc] init];
[paramDictionary setObject:#"5" forKey:#"q1"];
[paramDictionary setObject:#"10" forKey:#"q2"];
[paramDictionary setObject:#"15" forKey:#"q3"];
// this helps your web server know how many question-answers to expect, or you could hard code it into your business logic
[paramDictionary setObject:[NSNumber numberWithInteger:3] forKey:#"numberOfQA"];
MKNetworkOperation *op = [engine operationWithURLString:#"http://www.mywebserver.com/api/submitAnswers"
params:paramDictionary
httpMethod:#"POST"];
This will submit your answers for each of your question. You may have noticed I used q1, q2, q3.
These are for your web server code to identify each questions and extract the respective answers from them.
4) Server receives finished answers and commit them to database
So if you were using Symfony 2.0 PHP code, then something like:
// pseudo php function
public function saveAnswersAction()
{
$numOfQA = $_REQUEST['numberOfQA'];
for($i = 0; $i < $numOfQA; $i++)
{
// ----------------------------------------------------------------------
// looping through all the questions such as q1, q2, q3, q4, q5....
// by appending the counter variable to the question identifier
// ----------------------------------------------------------------------
$currentAnswer = $_REQUEST['q'.$i];
// use Doctrine to create new answer entities, and fill in their data
$answerEntity.answer = $currentAnswer;
$surveyEntity->addAnswerEntity($answerEntity);
// mark survey as complete so we can fetch all 'completed' surveys later
$surveyEntity.complete = true;
}
// tell Doctrine to commit changes to MySQL Database
// return HTTP OK status message
}
5) Now all that's left is for your master iPad app to make a HTTP POST request to get all surveys.
The process is the same with your iOS code making a HTTP POST requesting for all 'completed' survey entities from your web server.
The web server grabs them and return them as JSON encoded data.
Your app then receives the completed surveys with question answer like this:
surveys
{
{
questionNumber: 1,
questionAnswer: "5"
},
{
questionNumber: 2,
questionAnswer: "10"
},
{
questionNumber: 3,
questionAnswer: "15"
}
}
Now you use JSONKit to parse this JSON data. You should end up with a NSDictionary from JSONKit.
You can then go something like:
// pseudo code
-(void)displayCompletedSurveys
{
[MKNetworkOperationEngine doRequest:
...
^completionBlock {
// parse JSON data
NSDictionary *surveyData = [JSONKit dictionaryFromJSONData:data)
NSEnumerator *enumerator = [surveyData enumerator];
NSDictionary *currentQuestion = nil;
while([enumerator nextObject] != nil)
{
// do something with each of your question-answer e.g. show it on screen
}
}];
}
Points To Consider
Most of the code above are pseudo-codes. Your final real code would probably be much more in depth.
You'll need to build some master login into your app to prevent everyone from seeing the completed surveys.
Some Extra Information You Should Know
Here are some extra information to help you
JSONKit for fast JSON data decoding from your web server
MKNetworking or AFNetworking to submit your data to your web server
You need to know how to write web services to handle accepting the survey answers. I recommend learning a web framework like Symfony 2.0
Hope that helps.

Resources