I am using NSSharingService in my macOS Swift app. Is there any way to make sure the default mail client is configured with a valid account? - swift

I am using NSSharingService to prepare an email with attachment for the user of my macOS app. My code is:
let emailService = NSSharingService.init(named: NSSharingService.Name.composeEmail)
if emailService.canPerform(withItems: [emailBody, zipFileURL]) {
// email can be sent
DispatchQueue.main.async {
emailService.perform(withItems: [emailBody, zipFileURL])
}
} else {
// email cannot be sent
// Show alert with email address and instructions
self.showErrorAlert(with: 2803)
}
This works correctly, but if the code is executed on a fresh system, Apple Mail will be opened asking the user to configure an email account. Some users may not understand what is going on in this situation. Is there a way to ascertain if the default Email Client is configured, so that I can inform the user if it is not ? Thanks for your help.

Related

How to sent an email background with Swift code (macOS)

this code works fine but it pops a window, then have to click send. Can I send it in the background without pops a window?
Thank everybody!
import Cocoa
class SendEmail: NSObject {
static func send() {
let service = NSSharingService(named: NSSharingServiceNameComposeEmail)!
service.recipients = ["abc#dom.com"]
service.subject = "Vea software"
service.performWithItems(["This is an email for auto testing through code."])
}
}
SendEmail.send()
You can't do that, this would be quite not secure if a dev could sent any email from user's address without even letting him know
In background you can send a http request to your server which will send an email, but it will send it from your developer/organization/etc address, not from user's one ofc.

Teams not displaying email sent via SendGrid

I'm trying to post to a Teams channel via the email address using SendGrid. However, the emails I send via SendGrid are not appearing. I ended up adding my personal email address as well, and I do receive that one as well as seeing the Teams email address in the To: field. I can also see in SendGrid dashboard that the email was send and delivered to the Teams channel address. I have validated that this address is correct, and have also posted via my non-work email address to that channel, so I know it's not because of a typo or an external email address. My guess is that there is something in the email meta data that is making Teams reject the email? Anyone have ideas 1) why Teams won't post the email coming from SendGrid and 2) how I might modify my request in SendGrid so that it works? Also, alternative suggestions on sending emails (for free) from nodejs are welcome.
Here is the code I'm using to send the email for reference:
var msg = {
to: ['TEAMSCHANNELID#amer.teams.ms','mycompanyemail#company.com'], // ChatBot Support Team, General Channel
from: 'noreply#chatbotapimonitor.com',
subject: `Service Interruption Notice: API ${test} is down (via ${functionName})`,
text: `API ${test} failed with error ${error}`,
html: `API ${test} failed with error ${error}`
};
try {
await sgMail.send(msg);
} catch (err) {
context.log(err);
}
It turns out that Teams won't accept incoming emails if the From address domain does not match the actual "sent from" domain. I recognized this by the "Sent via sendgrid.net" message I saw in Outlook when the emails were sent to me as well.
I was able to get the out of the box Incoming Webhooks enabled, and using that instead of SendGrid emails got around the problem. I got the URL from the webhook configuration and then was able to call it like so:
var headers = { 'ContentType': 'application/json'}
var body = {
'#context': 'https://schema.org/extensions',
'#type': 'MessageCard',
'themeColor': 'FF0000',
'title':`API ${test} is down: Service Interruption Notice`,
'text': `API ${test} failed with error ${error}.\n\r\n\rReported by ${functionName} during test started on ${now.toString()}`
};
var res = await request({
url: url,
method: 'POST',
headers: headers,
json: body,
rejectUnauthorized: false
});
The themeColor doesn't appear in all channels, but I have it working as a nice red/green indicator on Teams desktop.
Perhaps your organization limits the sending ability to only certain domains? Someone with admin rights can check it under Teams settings => Email integration
yeah that's what I meant - making your own Connector app and side-loading. If you go ahead with it, please let me know - would love to know how it works out
Yes exactly making your own Connector would work.

Getting a CloudKit User's (Real) Email Address

I know I can look up a CloudKit user's unique ID like this:
CKContainer.default().fetchUserRecordID() { recordID, error in
if let recordID = recordID{
print(recordID.recordName) //_abcdef1234...
}
}
And then I can ask them for permission to grant access to their contact info like this:
CKContainer.default().requestApplicationPermission(.userDiscoverability){ status, error in
//...
}
And then I can look up their email address like this:
let userInfo = CKUserIdentityLookupInfo(userRecordID: recordID)
if let email = userInfo.emailAddress{
print(email) // user#example.com
}
But what I'm not clear on, is what is that email address? Is that their actual Apple ID email that Apple stores in their iCloud account? Or is it just whatever they happen to put in the Contacts app on their Mac or iOS device?
I want to know how reliable that email is. If ownership of that email address is not verified through the above techniques, then I'll pursue a different way of getting the user's email address.
Thanks for your help! :)

Swift2 Firebase: Is the email check done on the backend server? [duplicate]

Question says it all. In Firebase, how do I confirm email when a user creates an account, or, for that matter, do password reset via email.
I could ask more broadly: is there any way to send emails out from Firebase? E.g. notifications, etc. This isn't the kind of thing you would usually do client-side.
Update
Note that this was never a very secure way of handling email verification, and since Firebase now supports email verification, it should probably be used instead.
Original answer
I solved the email verification using the password reset feature.
On account creation I give the user a temporary (randomly generated) password. I then trigger a password reset which will send an email to the user with a link. The link will allow the user to set a new password.
To generate a random password you can use code similar to this:
function () {
var possibleChars = ['abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?_-'];
var password = '';
for(var i = 0; i < 16; i += 1) {
password += possibleChars[Math.floor(Math.random() * possibleChars.length)];
}
return password;
}
Note that this is happening on the client, so a malicious user could tamper with your logic.
This would need to be done outside of firebase. I store users at /users/ and keep a status on them (PENDING, ACTIVE, DELETED). I have a small service that monitors users of a PENDING status and sends out a confirmation email. Which has a link to a webservice I've created to update the user status to ACTIVE.
[Engineer at Firebase - Update 2014-01-27]
Firebase Simple Login now supports password resets for email / password authentication.
Each of the Simple Login client libraries has been given a new method for generating password reset emails for the specified email address - sendPasswordResetEmail() on the Web and Android, and sendPasswordResetForEmail() on iOS.
This e-mail will contain a temporary token that the user may use to log into their account and update their credentials. This token will expire after 24 hours or when the user changes their password, whichever occurs first.
Also note that Firebase Simple Login enables full configuration of the email template as well as the sending address (including whitelabel email from your domain for paid accounts).
To get access to this feature, you'll need to update your client library to a version of v1.2.0 or greater. To grab the latest version, check out https://www.firebase.com/docs/downloads.html.
Also, check out https://www.firebase.com/docs/security/simple-login-email-password.html for the latest Firebase Simple Login - Web Client docs.
As at 2016 July, you might not have to use the reset link etc. Just use the sendEmailVerification() and applyActionCode functions:
In short, below is basically how you'll approach this, in AngularJS:
// thecontroller.js
$scope.sendVerifyEmail = function() {
console.log('Email sent, whaaaaam!');
currentAuth.sendEmailVerification();
}
// where currentAuth came from something like this:
// routerconfig
....
templateUrl: 'bla.html',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn() // this throws an AUTH_REQUIRED broadcast
}]
}
...
// intercept the broadcast like so if you want:
....
$rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
if (error === "AUTH_REQUIRED") {
$state.go('login', { toWhere: toState });
}
});
....
// So user receives the email. How do you process the `oobCode` that returns?
// You may do something like this:
// catch the url with its mode and oobCode
.state('emailVerify', {
url: '/verify-email?mode&oobCode',
templateUrl: 'auth/verify-email.html',
controller: 'emailVerifyController',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn()
}]
}
})
// Then digest like so where each term is what they sound like:
.controller('emailVerifyController', ['$scope', '$stateParams', 'currentAuth', 'DatabaseRef',
function($scope, $stateParams, currentAuth, DatabaseRef) {
console.log(currentAuth);
$scope.doVerify = function() {
firebase.auth()
.applyActionCode($stateParams.oobCode)
.then(function(data) {
// change emailVerified for logged in User
console.log('Verification happened');
})
.catch(function(error) {
$scope.error = error.message;
console.log(error.message, error.reason)
})
};
}
])
And ooh, with the above approach, I do not think there's any need keeping the verification of your user's email in your user data area. The applyActionCode changes the emailVerified to true from false.
Email verification is important when users sign in with the local account. However, for many social authentications, the incoming emailVerified will be true already.
Explained more in the article Email Verification with Firebase 3.0 SDK
What I did to work around this was use Zapier which has a built in API for firebase. It checks a location for added child elements. Then it takes the mail address and a verification url from the data of new nodes and sends them forwards. The url points back to my angular app, which sets the user email as verified.
As I host my app files in firebase, I don't need have to take care of any servers or processes doing polling in the background.
There is a delay, but as I don't block users before verifying mails it's ok. Zapier has a free tier and since I don't have much traffic it's a decent workaround for time being.
The new Firebase SDK v3 appears to support email address verification, see here (put your own project id in the link) but it doesn't appear to be documented yet.
I have asked the question on SO here
See #SamQuayle's answer there with this link to the official docs.
As noted by various others Firebase does now support account related emails but even better, as of 10 days ago or so it also supports sending any kind of email via Firebase Functions. Lots of details in the docs and example code here.
I used following code to check the email verification after creating new account.
let firAuth = FIRAuth.auth()
firAuth?.addAuthStateDidChangeListener { auth, user in
if let loggedUser = user {
if loggedUser.emailVerified == false {
loggedUser.sendEmailVerificationWithCompletion({ (error) in
print("error:\(error)")
})
}
else {
print(loggedUser.email)
}
} else {
// No user is signed in.
print("No user is signed in.")
}
}
I used MandrillApp. You can create an API key that only allows sending of a template. This way even thought your key is exposed it can't really be abused unless someone wants to fire off tonnes of welcome emails for you.
That was a hack to get myself off the ground. I'm now enabling CORS from a EC2 that uses the token to verify that the user exists before extending them a welcome via SES.

How to handle Email on Google TV

My HoneyComb application runs on tablets and Google TV. I have setting to send email in my settings fragment, but it returns error of "No app can handle this function."
Is there a way to send email to browser through my application if there is no client (createChooser) available?
I also tried to display a summary of the customer service email, but summary is not working on HoneyComb. I was trying this so I could have disabled Intent on tv.
Is there a way to send email to browser through my application if there is no client (createChooser) available?
Not unless you know the specific email Web app and all of its details, and that email Web app supports some sort of direct-email-sending capability.
Either prompt the user to install an email app, or send the email yourself (e.g., JavaMail), or do not use email for communications on Google TV. I would expect few Google TV users to be using email on their televisions, so you need to plan accordingly.
Google TV includes a default, stub email app, so the system will appear to have an email app installed, even when there is none. There's a special check necessary to detect the stub:
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("plain/text"); // special mime legacy for gmail; others work
List<ResolveInfo> match = getPackageManager().queryIntentActivities(emailIntent, 0);
boolean hasEmailer = match.size() > 0;
Log.w("thuuz", "has plain/text Emailer: " + hasEmailer);
if (match.size() == 1) {
ResolveInfo info = match.get(0);
boolean real = true;
if (info.activityInfo.packageName.startsWith("com.google.android.tv.frameworkpackagestubs"))
real = false;
Log.w("thuuz", "has *real* Emailer: " + real);
}