tags:

views:

102

answers:

4

I wrote a code to recover passwrod in my website.The user enter his email address and we send a new password to him.In additcion,we also change his password in DB to newest password.

Problem: If code for send mail fails,i cant change his password in DB,and if code to change password fails i cant send mail.

Take a look:

public bool RecoverPassword(string email)
        {
            try
            {
                SceLoginMail sceEmail = new SceLoginMail(email, "Recuperação de senha", 5);
                ChangeUserPassword(sceEmail.NovaSenha, email);
                sceEmail.SendEmail();
                sceUsers.CommitOrRollBack(true);
                return true;
            }
            catch (Exception ex)
            {
                sceUsers.CommitOrRollBack(false);
                return false;
            }
        }

I try to rollback in DB if an exceptions occurs in SendEmail method.But,i cant "RollBack" the SendMail method if an exceptions throws in CommitOrRollback method.If so,system will send the mail and wont change it on DB.

Any ideias?

+3  A: 

Don't send the email until after the database transaction (and anything else that affects the validity of the new password) has completed. That way, if it throws an exception, the SendEmail() call never gets executed.

djacobson
Then if an exception fire in SendMail() method,i did change his password,and didnt send the mail.The use wont be able to acess the system,cause his password has changed and he dont know to what.
@ozsenegal - provide an email address for customer support for those marginal cases. If network outages and other technical problems are a real concern, use message queues to send the emails out-of-band. In the end though, there's only so much a technical solution can do here: the user may just have provided an invalid (or incorrect) address.
Jeff Sternal
@ozsenegal - Sure, but you can trap and (presumably, unless your mailserver is on fire) recover from / retry the email. If you absolutely cannot accept **either** password change or SendEmail occurring unless **BOTH** succeed, you'll need to implement more-sophisticated logic for determining when to truly commit the DB change than a simple rollback in the exception handler.
djacobson
+2  A: 

Doesn't matter much if you assign a new password and it doesn't get sent for some reason. The user already doesn't know his/her password. The email won't show up, and they will request it again. So commit the DB, and do a send, in that order.

EJB
A: 

See, the action to request for password change and request to get email for the changed password is separate phenomenon.

When user requests the change of password, you just invoke the statement to update the database with the new password. After its updated, try sending the mail.

It is better to have a Mail Outbox in. So that when the email sending fails, it is stored in the database table outbox and which you should periodically try out after a Threshold time.

This would ensure that you keep trying sending that mail to the user.

abhishek
+1  A: 

Instead of resetting the password in response to the "I lost my password" request, send the user an email with a unique, single-use, time-bounded reset URL. Only reset the password if that URL is visited within the allowed time.

This has two benefits:

  1. The password is only reset if the email is successfully sent and received.
  2. If someone other than the person the account belongs performs the "I lost my password" request (whether by accident or on purpose), the legitimate account-holder doesn't have his/her password unexpectedly become invalid.
ThatBlairGuy