A send failure can leave a registration record that cannot be retried
Source references: 4The example writes the user and email mappings before awaiting the external mail send. Motoko commits preceding state at an await boundary, so a later trap in the error branch does not undo those writes. A subsequent attempt is rejected as already registered.
A temporary mail failure can permanently reserve the caller and address without delivering a verification link, leaving inconsistent account data and blocking registration.
The example updates users and emailToPrincipal before awaiting email delivery, then traps on a send error. Under Motoko's commit-at-await behavior, that trap does not roll back the earlier committed map updates, while a retry is rejected by the existing-user or existing-email checks. Copying this flow can therefore strand a user without a self-service retry. Users can ask for failure compensation, a separate resend endpoint, or an explicit retryable state.
public shared ({ caller }) func registerUser(email : Text, name : Text) : async () { if (users.containsKey(caller)) { Runtime.trap("User already registered"); }; if (emailToPrincipal.containsKey(email)) { Runtime.trap("Email already registered"); };Show 3 other places
}; users.add(caller, user); emailToPrincipal.add(email, caller); let result = await EmailClient.sendVerificationEmail( "no-reply", [email], "Welcome to Our Service", "Hello " # name # ",<br><br>Thank you for registering with our service. Please <a href=\"{{VERIFICATION_URL}}\">click here</a> to verify your email address<br><br>Best regards,<br>The Team", ); switch (result) { case (#ok) {}; case (#err(error)) { Runtime.trap("Couldn't send verification email: " # error); }; }; }; public shared ({ caller }) func registerUser(email : Text, name : Text) : async () { if (users.containsKey(caller)) { Runtime.trap("User already registered"); }; if (emailToPrincipal.containsKey(email)) { Runtime.trap("Email already registered"); };