Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Support for sending an email with a link the recipient can click to prove they own the email address.
.claude/skills/aiskillstore-extension-email-verification/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | -42% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 20% | 0% |
| case-07 | ✗→✓ | ▲ Improved | -17% | 0% |
| case-08 | ✗→✓ | ▲ Improved | -13% | 0% |
| case-09 | ✗→✓ | ▲ Improved | -24% | 0% |
Email verification extension for Caffeine AI.
This skill adds email address verification via a click-to-verify link. The MixinEmailVerification handles the verification callback; verifiedEmails tracks verified addresses.
Use the prefabricated module mo:caffeineai-email-verification/verifiedEmails.mo which cannot be modified.
mo:caffeineai-email-verification/verifiedEmails.momodule { public type State = { var verifiedEmails : Set.Set<Text>; }; public func new() : State { { var verifiedEmails = Set.empty<Text>(); }; }; public func contains(state : State, email : Text) : Bool; public func iter(state : State) : Iter.Iter<Text>; public func size(state : State) : Nat; };
To check whether an email is verified use the contains function. Do NOT try to track the email verification status independently by storing it against the user profile.
Use the prefabricated module mo:caffeineai-email-verification/verificationMixin.mo which cannot be modified.
The MixinEmailVerification handles calls to the verification link to verify an email address.
mo:caffeineai-email-verification/verificationMixin.moimport MixinEmailVerification "mo:caffeineai-email-verification/verificationMixin";
mo:caffeineai-email/emailClient.momodule { public type SendResult = { #ok; #err : Text; }; public func sendVerificationEmail( fromUsername : Text, recipients : [Text], subject : Text, htmlBody : Text, ) : async SendResult; };
motoko filepath=src/backend/main.moimport Map "mo:core/Map"; import Runtime "mo:core/Runtime"; import Principal "mo:core/Principal"; import Text "mo:core/Text"; import EmailClient "mo:caffeineai-email/emailClient"; import MixinEmailVerification "mo:caffeineai-email-verification/verificationMixin"; import VerifiedEmails "mo:caffeineai-email-verification/verifiedEmails"; actor { // Stores which emails are verified let verifiedEmails = VerifiedEmails.new(); // User profiles storage let users = Map.empty<Principal, User>(); // Email to principal mapping for uniqueness check let emailToPrincipal = Map.empty<Text, Principal>(); // Handles the verification link and updates the verifiedEmails store include MixinEmailVerification(verifiedEmails); type User = { name : Text; email : Text; }; 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"); }; let user : User = { name; email; }; 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 isEmailVerified() : async Bool { switch (users.get(caller)) { case (null) { Runtime.trap("User not registered"); }; case (?user) { VerifiedEmails.contains(verifiedEmails, user.email); }; }; }; };
If there is a UI for the admin to enter the content of a verification email then indicate that the placeholder text {{VERIFICATION_URL}} must be present in the email body.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 36,069 | 16,625 | -54% | 1 | 1 | 0% | 6,373 | 3,679 | -42% | 0 | 0 | — |
case-02 | fail→fail | 24,860 | 13,462 | -46% | 1 | 1 | 0% | 4,021 | 2,963 | -26% | 0 | 0 | — |
case-03 | fail→pass | 26,010 | 20,446 | -21% | 1 | 1 | 0% | 3,758 | 4,516 | +20% | 0 | 0 | — |
case-04 | pass→pass | 21,412 | 14,034 | -34% | 1 | 1 | 0% | 2,993 | 3,002 | +0% | 0 | 0 | — |
case-05 | pass→pass | 20,889 | 9,531 | -54% | 1 | 1 | 0% | 2,712 | 2,864 | +6% | 0 | 0 | — |
case-06 | pass→pass | 19,480 | 24,530 | +26% | 1 | 1 | 0% | 2,747 | 5,364 | +95% | 0 | 0 | — |
case-07 | fail→pass | 22,327 | 11,602 | -48% | 1 | 1 | 0% | 2,951 | 2,463 | -17% | 0 | 0 | — |
case-08 | fail→pass | 20,462 | 11,258 | -45% | 1 | 1 | 0% | 2,811 | 2,444 | -13% | 0 | 0 | — |
case-09 | fail→pass | 14,972 | 9,788 | -35% | 1 | 1 | 0% | 2,596 | 1,984 | -24% | 0 | 0 | — |
case-10 | fail→pass | 19,248 | 3,223 | -83% | 1 | 1 | 0% | 3,261 | 1,767 | -46% | 0 | 0 | — |
case-11 | fail→pass | 7,602 | 10,598 | +39% | 1 | 1 | 0% | 1,322 | 2,293 | +73% | 0 | 0 | — |
case-12 | fail→pass | 17,048 | 6,722 | -61% | 1 | 1 | 0% | 2,463 | 2,617 | +6% | 0 | 0 | — |
case-13 | fail→pass | 15,490 | 3,843 | -75% | 1 | 1 | 0% | 2,547 | 1,837 | -28% | 0 | 0 | — |
case-14 | fail→pass | 15,372 | 4,988 | -68% | 1 | 1 | 0% | 2,698 | 2,182 | -19% | 0 | 0 | — |
case-15 | fail→pass | 19,479 | 5,952 | -69% | 1 | 1 | 0% | 2,149 | 2,374 | +10% | 0 | 0 | — |
case-16 | fail→pass | 12,694 | 8,495 | -33% | 1 | 1 | 0% | 1,148 | 1,647 | +43% | 0 | 0 | — |
case-17 | fail→pass | 12,574 | 3,629 | -71% | 1 | 1 | 0% | 1,227 | 1,776 | +45% | 0 | 0 | — |
case-18 | fail→fail | 37,704 | 17,020 | -55% | 1 | 1 | 0% | 3,036 | 3,318 | +9% | 0 | 0 | — |
case-19 | fail→pass | 10,223 | 2,785 | -73% | 1 | 1 | 0% | 1,580 | 1,681 | +6% | 0 | 0 | — |
case-20 | fail→pass | 11,941 | 13,298 | +11% | 1 | 1 | 0% | 2,300 | 2,854 | +24% | 0 | 0 | — |
case-21 | pass→pass | 22,565 | 4,312 | -81% | 1 | 1 | 0% | 2,470 | 2,034 | -18% | 0 | 0 | — |
case-22 | fail→pass | 21,783 | 9,330 | -57% | 1 | 1 | 0% | 2,313 | 2,130 | -8% | 0 | 0 | — |
case-23 | fail→pass | 13,001 | 4,045 | -69% | 1 | 1 | 0% | 1,489 | 1,916 | +29% | 0 | 0 | — |
case-24 | fail→pass | 24,338 | 12,026 | -51% | 1 | 1 | 0% | 3,430 | 2,745 | -20% | 0 | 0 | — |
case-25 | fail→pass | 14,756 | 2,723 | -82% | 1 | 1 | 0% | 1,520 | 1,668 | +10% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted. The headline lift of +76 percentage points is the difference between those two pass rates over the 25 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.