4

Today I set up mailgun to enable password reset and verification emails on my parse-server.

After hour of troubleshooting why verification email is not working, I tried password reset and discovered that password reset was working fine.

I have tried to send a verification email to new users and old users without luck. Mailgun adapter setup should be fine, as it can send the password reset emails. At the moment I cannot find a solution on the verification email.

The server is running on Bluemix (similar to Heroku). The following environmental variables are set (I do not list everything as it includes keys and since reset password is working, they must be set correctly):

EMAIL_VERIFY_TOKEN_VALIDITY_DURATION = 7200

VERIFY_USER_EMAIL = true

My index.js file:

'use strict';

// Required Libs
require('dotenv').config()

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var http = require('http');

// Start Express
var app = express();

// Validate Keys
if (!process.env.APP_ID) {
  throw 'Please apply the Application ID from Parse.com';
}

if (!process.env.MASTER_KEY) {
  throw 'Please apply the Master Key from Parse.com';
}

if (process.env.DATABASE_URI) {
  var databaseUri = process.env.DATABASE_URI;
} else if (process.env.VCAP_SERVICES) {
  var vcapServices = JSON.parse(process.env.VCAP_SERVICES);
  const pattern = /mongo/i;
  for (var i = 0; i < vcapServices['user-provided'].length; i++) {
    if (vcapServices['user-provided'][i].name.search(pattern) >= 0 ||
      vcapServices['user-provided'][i].credentials.uri.search(pattern) >= 0) {
      var databaseUri = 'mongodb://' +
        vcapServices['user-provided'][i].credentials.user +
        ':' + vcapServices['user-provided'][i].credentials.password +
        '@' + vcapServices['user-provided'][i].credentials.uri;
      break;
    }
  }

} else {
  throw 'Please provide DATABASE_URI to an instance of MongoDB or deploy to Bluemix with a Compose MongoDB service';
}

// Server Location
var port      = process.env.VCAP_APP_PORT || process.env.PORT || 1337;
var host      = process.env.VCAP_APP_HOST || 'localhost';
var mountPath = process.env.PARSE_MOUNT || '/';

//var serverUrl = ((process.env.HTTPS) ? 'https://' : 'http://') + host + ':' + port + mountPath;
var publicServerUrlRoot = process.env.PUBLIC_SERVER_URL || host
var publicServerUrl = ((process.env.HTTPS) ? 'https://' : 'http://') + publicServerUrlRoot + mountPath;

// Specify the connection string for your mongodb database
// and the location to your Parse cloud code
var parseConfig = {
  databaseURI: databaseUri,
  appId: process.env.APP_ID,
  masterKey: process.env.MASTER_KEY,
  cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
  serverURL: publicServerUrl,
  // Setup email verification
  verifyUserEmail: process.env.VERIFY_USER_EMAIL || true,
  emailVerifyTokenValidityDuration: process.env.EMAIL_VERIFY_TOKEN_VALIDITY_DURATION || 2 * 60 * 60,
  publicServerURL: publicServerUrl,
  appName: process.env.APP_NAME,
  emailAdapter: {
    module: 'parse-server-simple-mailgun-adapter',
    options: {
      // The address that your emails come from
      fromAddress: process.env.DEFAULT_FROM_ADDRESS,
      // Your domain from mailgun.com
      domain: process.env.MAILGUN_DOMAIN,
      // Your API key from mailgun.com
      apiKey: process.env.MAILGUN_API_KEY,
    }
  }
};


// Optional Keys
if (process.env.FILE_KEY) {
  // String
  parseConfig.fileKey = process.env.FILE_KEY;
}

if (process.env.CLIENT_KEY) {
  // String
  parseConfig.clientKey = process.env.CLIENT_KEY;
}

if (process.env.JS_KEY) {
  // String
  parseConfig.javascriptKey = process.env.JS_KEY;
}

if (process.env.REST_KEY) {
  // String
  parseConfig.restAPIKey = process.env.REST_KEY;
}

if (process.env.DOTNET_KEY) {
  // String
  parseConfig.dotNetKey = process.env.DOTNET_KEY;
}

if (process.env.ALLOW_CLIENT_CLASS_CREATION) {
  // Boolean
  parseConfig.allowClientClassCreation = process.env.ALLOW_CLIENT_CLASS_CREATION;
}

if (process.env.ENABLE_ANONYMOUS_USERS) {
  // Boolean
  parseConfig.enableAnonymousUsers = process.env.ENABLE_ANONYMOUS_USERS;
}

if (process.env.OAUTH) {
  // Object: https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth
  parseConfig.oauth = process.env.OAUTH;
}

if (process.env.FACEBOOK_APP_IDS) {
  // Array
  parseConfig.facebookAppIds = process.env.FACEBOOK_APP_IDS;
}

// Create Parse Server instance
var api = new ParseServer(parseConfig);

// Serve the Parse API on the / URL prefix
app.use(mountPath, api);

// And listen to requests
app.listen(port, function() {
  //console.log('parse server url ' + serverUrl);
  console.log('parse public server url ' + publicServerUrl);
  console.log('parse-server running on port ' + port + '.');
});

require("cf-deployment-tracker-client").track();

To verify the user email I use two methods:

1. New user sign up

I have anonymous users enabled and I have subclassed PFSignUpViewController. The only thing the subclassing does is to changed the colors and fonts. The server side is set to verify user emails, so an email should be sent when a user is signed up automatically.

On sign up I get the following on the server log:

RTR/1kitespotterparseserver.mybluemix.net - [17/10/2016:08:27:35.196 +0000] "POST /parse/users HTTP/1.1" 201 85 116 "-" "KiteSpotter/623 CFNetwork/758.4.3 Darwin/15.5.0" 169.54.202.26:49150 x_forwarded_for:"37.6.22.73" x_forwarded_proto:"https" vcap_request_id:58e37dd1-42ac-4c08-4704-44983ab869fb response_time:0.429154539 app_id:9fe504a4-346d-4c67-a268-ef61a25cc006 x_global_transaction_id:"3652227649"

Unfortunately no email is coming and nothing is logged on mailgun. So the server never reaches mailgun.

2. Current User Resent Verification Email

To resent verification email to the user I use the following code (on the client side):

class func resendVerificationEmail(_ block: @escaping (_ success: Bool) -> Void) {
    if let email = PFUser.current()?.email {
        PFUser.current()?.email = email+".verify"
        PFUser.current()?.saveInBackground(block: { (success, error) -> Void in
            if success {
                Log.info?.message("Verify Email. Temp email saved.")
                PFUser.current()?.email = email
                PFUser.current()?.saveInBackground(block: { (success, error) in
                    if success {
                        Log.info?.message("Verify Email. New email saved.")
                    } else {
                        Log.error?.message("Verify Email. New email save failed.\n\(error?.localizedDescription)")
                    }
                    block(success)
                })
            } else {
                Log.error?.message("Verify Email. Temp email save failed.")
                block(success)
            }
        })
    }
}

--

class func verifyEmailAction(_ notifyVC: UIViewController?) -> UIAlertAction {
    let emailVerificationAction = UIAlertAction(title: "Verify Email", style: UIAlertActionStyle.default) { (action) in
        ParseLoginHelper.resendVerificationEmail({ (success) -> Void in
            let alertController: UIAlertController
            if success {
                alertController = UIAlertController(title: "Verification Email Sent", message: "Sent to \(StringOrEmpty(PFUser.current()?.email))\nPlease check your emails", preferredStyle: .alert)
            } else {
                alertController = UIAlertController(title: "Verification Email Failed", message: nil, preferredStyle: .alert)
            }
            let OKAction = UIAlertAction(title: "Dismiss", style: .default, handler: nil)
            alertController.addAction(OKAction)
            notifyVC?.present(alertController, animated: true, completion: nil)
        })
    }
    return emailVerificationAction
}

Once this is sent to the parse server the following appears on the server log:

RTR/0kitespotterparseserver.mybluemix.net - [17/10/2016:08:30:14.104 +0000] "PUT /parse/classes/_User/clCOWBsNLz HTTP/1.1" 200 72 40 "-" "KiteSpotter/623 CFNetwork/758.4.3 Darwin/15.5.0" 169.54.202.27:33533 x_forwarded_for:"37.6.22.73" x_forwarded_proto:"https" vcap_request_id:4c3e8056-9d70-4b1d-5c15-8a97c616f5ad response_time:0.449085887 app_id:9fe504a4-346d-4c67-a268-ef61a25cc006 x_global_transaction_id:"2500672239" 2016-10-17T11:30:14.554+0300
RTR/0kitespotterparseserver.mybluemix.net - [17/10/2016:08:30:14.959 +0000] "PUT /parse/classes/_User/clCOWBsNLz HTTP/1.1" 200 37 40 "-" "KiteSpotter/623 CFNetwork/758.4.3 Darwin/15.5.0" 169.54.202.27:33640 x_forwarded_for:"37.6.22.73" x_forwarded_proto:"https" vcap_request_id:3bbd5653-05f3-46ce-79ad-9772741fbdcf response_time:0.631187244 app_id:9fe504a4-346d-4c67-a268-ef61a25cc006 x_global_transaction_id:"3241831095"

On the iOS app, I get a pop up with "Verification Email Sent" and the following log:

2016-10-17 11:30:14.858 am EEST |    INFO | ParseLogin.swift:51 - Verify Email. Temp email saved.
2016-10-17 11:30:15.953 am EEST |    INFO | ParseLogin.swift:55 - Verify Email. New email saved.

Again nothing is logged on mailgun.

This was a trick that was working fine on parse.com.

Password Reset

If I request a password reset for the user. This is done from the parse sign up page. I get the following:

Server Log

RTR/1kitespotterparseserver.mybluemix.net - [17/10/2016:08:38:03.159 +0000] "POST /parse/requestPasswordReset HTTP/1.1" 200 37 2 "-" "KiteSpotter/623 CFNetwork/758.4.3 Darwin/15.5.0" 169.54.202.26:52006 x_forwarded_for:"37.6.22.73" x_forwarded_proto:"https" vcap_request_id:f37a23a9-17eb-473e-4439-dd6b3f8f2176 response_time:0.140150335 app_id:9fe504a4-346d-4c67-a268-ef61a25cc006 x_global_transaction_id:"2067630247"

Client Log

Nothing

Mailgun Log

10/17/16 04:38 AM   Delivered: postmaster@mg.paz-labs.com → kitespotter2@paz-labs.com 'Password Reset for KiteSpotter'  
10/17/16 04:38 AM   Accepted: postmaster@mg.paz-labs.com → kitespotter2@paz-labs.com 'Password Reset for KiteSpotter'

And an email with instruction on how to reset my password.

zirinisp
  • 9,971
  • 5
  • 32
  • 38
  • Do you see any errors in `cf logs yourappname --recent`? Please recreate the problem and post the output in your question so maybe someone can spot what is the problem. – Alex da Silva Oct 14 '16 at 22:21
  • @AlexdaSilva Thank you for the comment. I updated question with logs and more details on my setup. Unfortunately it is hard to make a sample app with the problem, as there private keys involved in two servers and one application. – zirinisp Oct 17 '16 at 08:42
  • FWIW - verify that u have installed the mailgun module for verification ( parse-server-simple-mailgun-adapter ) – Robert Rowntree Oct 24 '16 at 13:50
  • https://github.com/ParsePlatform/parse-server/blob/master/src/Controllers/UserController.js#L45 in a node debugger may help. – Robert Rowntree Oct 24 '16 at 14:07
  • @RobertRowntree I am sure it is installed as password reset is working fine – zirinisp Oct 25 '16 at 11:48
  • @RobertRowntree For the node debugger as I am not familiar with node.js can you give me some guidance – zirinisp Oct 25 '16 at 11:49
  • Usercontroller.VerifyEmail() should be getting invoked on changes to _User. There are several options for debugger on node . u may want to implement one of them to watch that method's exec. – Robert Rowntree Oct 25 '16 at 19:19
  • I tried to fork parse_server and then edit and inject console.log on the user controller.verifyemail. Bluemix did not accept a private repo or to be clear after spending a day on something that the my level of experience is almost none, I did not find a way for bluemix to accept a private repo. Will look into it further and come back with an update – zirinisp Oct 31 '16 at 10:27
  • It was a silly typo that the compile did not complaint about and the runtime did not crash – zirinisp Oct 31 '16 at 12:37

1 Answers1

1

The solution was very simple. It was a typo on the index.js file.

  verifyUserEmail: process.env.VERIFY_USER_EMAIL || true,

should be

  verifyUserEmails: process.env.VERIFY_USER_EMAIL || true,

In my opinion, I should be getting a compile or runtime error on the first one which I did not get.

Prashant Ghimire
  • 4,890
  • 3
  • 35
  • 46
zirinisp
  • 9,971
  • 5
  • 32
  • 38