├── logo.png ├── banner.png ├── themes ├── v1.PNG ├── v2.PNG ├── v3.PNG ├── v4.png ├── v5.png └── v6.PNG ├── analysis_options.yaml ├── .metadata ├── .gitignore ├── pubspec.yaml ├── LICENSE ├── CHANGELOG.md ├── templates ├── v4.html ├── v6.html ├── v5.html ├── v3.html ├── v2.html └── v1.html ├── example └── example.md ├── README.md └── lib └── email_otp.dart /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohit-chouhan/email_otp/HEAD/logo.png -------------------------------------------------------------------------------- /banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohit-chouhan/email_otp/HEAD/banner.png -------------------------------------------------------------------------------- /themes/v1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohit-chouhan/email_otp/HEAD/themes/v1.PNG -------------------------------------------------------------------------------- /themes/v2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohit-chouhan/email_otp/HEAD/themes/v2.PNG -------------------------------------------------------------------------------- /themes/v3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohit-chouhan/email_otp/HEAD/themes/v3.PNG -------------------------------------------------------------------------------- /themes/v4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohit-chouhan/email_otp/HEAD/themes/v4.png -------------------------------------------------------------------------------- /themes/v5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohit-chouhan/email_otp/HEAD/themes/v5.png -------------------------------------------------------------------------------- /themes/v6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohit-chouhan/email_otp/HEAD/themes/v6.PNG -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 5464c5bac742001448fe4fc0597be939379f88ea 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 25 | /pubspec.lock 26 | **/doc/api/ 27 | .dart_tool/ 28 | .packages 29 | build/ 30 | test/ 31 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: email_otp 2 | description: A fast & simple email authentication OTP sender and verification flutter package. 3 | version: 3.1.0 4 | homepage: https://rohitchouhan.com 5 | repository: https://github.com/rohit-chouhan/email_otp 6 | 7 | environment: 8 | sdk: ">=2.16.2 <4.0.0" 9 | flutter: ">=1.17.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | http: ^1.6.0 15 | mailer: ^6.6.0 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | flutter_lints: ^4.0.0 21 | 22 | screenshots: 23 | - description: "Email OTP Logo" 24 | path: logo.png 25 | 26 | topics: 27 | - email 28 | - otp 29 | - smtp 30 | - authentication 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Rohit Chouhan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 3.1.0 2 | - **BREAKING CHANGE**: Removed server-side dependency. Now sends emails directly from the client. 3 | - **REQUIRED**: You must now provide your own SMTP credentials using `EmailOTP.setSMTP()`. 4 | - Added remote template fetching from GitHub via jsDelivr. 5 | - Added dependency `mailer` and `http`. 6 | 7 | 8 | - OTP expiry option added 9 | - `getOTP` changed into method `getOTP()` 10 | - `isExpired()` method added to validate otp expiry time 11 | - `v6` New theme added 12 | - bugs fixed 13 | 14 | ## 3.0.1 15 | 16 | - Documentation broken image link fixed 17 | 18 | ## 3.0.0 19 | 20 | - Various bug fixes have been implemented. 21 | - Documentation has been improved for better clarity and ease of use. 22 | - New features added. 23 | - Added new themes: v4 and v5. 24 | - Replaced `setConfig()` with `config()`. 25 | - In the `sendOTP()` method, use the `userEmail:` property. 26 | - Removed the `auth:` property from the `setSMTP` method; it is no longer needed. 27 | - You can now easily pass the OTP type using the `OTPType` enum class. 28 | - You can now pass the `smtp_port:` value easily using the `EmailPort` enum class. 29 | - You can now pass the `smtp_secure:` value easily using the `SecureType` enum class. 30 | - You can now select themes using the `EmailTheme` enum class. 31 | 32 | ## 2.1.2 33 | 34 | - bugs fixed 35 | - theme customization [added] 36 | 37 | ## 2.1.1 38 | 39 | - error handling [added] 40 | 41 | ## 2.1.0 42 | 43 | - bug fixed 44 | - Customize Template [added] 45 | 46 | ## 2.0.1 47 | 48 | - bug fixed 49 | 50 | ## 2.0.0 51 | 52 | - bug fixed 53 | - new cool email template 54 | - new feature added for custom SMTP 55 | 56 | ## 1.0.4 57 | 58 | - format fixed 59 | 60 | ## 1.0.3 61 | 62 | - otpType property added. 63 | 64 | ## 1.0.2 65 | 66 | - Changed class Name from Email_OTP to EmailOTP. 67 | - otpLength property added. 68 | 69 | ## 1.0.1 70 | 71 | - readme changed. 72 | 73 | ## 1.0.0 74 | 75 | - initial release. 76 | -------------------------------------------------------------------------------- /templates/v4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 67 | {{appName}} OTP 68 | 69 | 70 | 71 |
72 |
73 |
74 |
75 |

{{appName}}

76 |
77 |
78 |

Your One-Time Password (OTP) is:

79 |
{{otp}}
80 |

Please use this OTP to complete your login process. Do not share this code with anyone.

81 |
82 | 86 |
87 | 88 | 89 | -------------------------------------------------------------------------------- /templates/v6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 61 | 62 | 63 | 64 |
65 |
66 |

67 | {{appName}} 68 |

69 |
70 |
71 |
72 |

Dear User,

73 |

Your One-Time Password (OTP) is:

74 |
75 | {{otp}} 76 |
77 |

Please use this OTP to complete your login process. Do not share this code with anyone.

78 |

Thank you for using {{appName}}!

79 |
80 | 83 |
84 | 85 | 86 | -------------------------------------------------------------------------------- /example/example.md: -------------------------------------------------------------------------------- 1 | Here the example of all method, enjoy coding 😃 2 | ```dart 3 | import 'package:email_otp/email_otp.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | void main() { 7 | EmailOTP.config( 8 | appName: 'MyApp', 9 | otpType: OTPType.numeric, 10 | emailTheme: EmailTheme.v1, 11 | ); 12 | 13 | /* 14 | EmailOTP.setSMTP( 15 | host: '', 16 | emailPort: EmailPort.port587, 17 | secureType: SecureType.tls, 18 | username: '', 19 | password: '', 20 | ); 21 | */ 22 | 23 | /* 24 | EmailOTP.setTemplate( 25 | template: ''' 26 |
27 |
28 |

{{appName}}

29 |

Your OTP is {{otp}}

30 |

This OTP is valid for 5 minutes.

31 |

Thank you for using our service.

32 |
33 |
34 | ''', 35 | ); 36 | */ 37 | runApp( 38 | const MaterialApp( 39 | debugShowCheckedModeBanner: false, 40 | home: HomePage(), 41 | ), 42 | ); 43 | } 44 | 45 | class HomePage extends StatelessWidget { 46 | const HomePage({super.key}); 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | TextEditingController emailController = TextEditingController(); 51 | TextEditingController otpController = TextEditingController(); 52 | return Scaffold( 53 | appBar: AppBar(title: const Text('Email OTP')), 54 | body: ListView( 55 | children: [ 56 | TextFormField(controller: emailController), 57 | ElevatedButton( 58 | onPressed: () async { 59 | if (await EmailOTP.sendOTP(email: emailController.text)) { 60 | ScaffoldMessenger.of(context).showSnackBar( 61 | const SnackBar(content: Text("OTP has been sent"))); 62 | } else { 63 | ScaffoldMessenger.of(context).showSnackBar( 64 | const SnackBar(content: Text("OTP failed sent"))); 65 | } 66 | }, 67 | child: const Text('Send OTP'), 68 | ), 69 | TextFormField(controller: otpController), 70 | ElevatedButton( 71 | onPressed: () => EmailOTP.verifyOTP(otp: otpController.text), 72 | child: const Text('Verify OTP'), 73 | ), 74 | ], 75 | ), 76 | ); 77 | } 78 | } 79 | 80 | ``` -------------------------------------------------------------------------------- /templates/v5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 70 | {{appName}} OTP 71 | 72 | 73 | 74 |
75 |
76 |
77 |
78 |

{{appName}}

79 |
80 |
81 |

Dear User,

82 |

Your One-Time Password (OTP) is:

83 |
{{otp}}
84 |

Please use this OTP to complete your login process. Do not share this code with anyone.

85 |

Thank you for using {{appName}}!

86 |
87 | 90 |
91 | 92 | 93 | -------------------------------------------------------------------------------- /templates/v3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 97 | 98 | 99 | 100 |
101 |
102 | 103 |

104 | {{appName}} 105 |

106 |
107 |
108 |
109 |

Your requested OTP for 110 | {{appName}} 111 |


112 | 113 | {{otp}} 114 | 115 |
116 |
117 | 121 |
122 | 123 | 124 | -------------------------------------------------------------------------------- /templates/v2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 78 | 79 |
20 | 22 | 23 | 24 | 25 | 26 | 32 | 33 | 34 | 35 | 36 | 37 | 63 | 64 | 65 | 66 | 67 | 72 | 73 | 74 | 75 | 76 |
 
27 | 28 | logo 30 | 31 |
 
38 | 40 | 41 | 42 | 43 | 44 | 57 | 58 | 59 | 60 | 61 |
 
45 |

47 | {{appName}}

48 | 50 |

51 | Your Requsted OTP for {{appName}} is 52 |

53 | {{otp}} 55 | 56 |
 
62 |
 
68 |

70 | © www.rohitchouhan.com

71 |
 
77 |
80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Email OTP is a Flutter package designed to simplify email authentication using one-time passwords (OTPs). With Email OTP, you can effortlessly generate OTPs and send them to users' email addresses, ensuring secure identity verification. This package offers an efficient and secure method for incorporating email-based OTP authentication into your Flutter applications. 2 | 3 | ![Email OTP Banner](https://raw.githubusercontent.com/rohit-chouhan/email_otp/main/banner.png) 4 | 5 | [![GitHub](https://img.shields.io/badge/Rohit_Chouhan-GitHub-black?logo=github)](https://www.github.com/rohit-chouhan) 6 | _[![Sponsor](https://img.shields.io/badge/Sponsor-Become_A_Sponsor-blue?logo=githubsponsors)](https://github.com/sponsors/rohit-chouhan)_ 7 | 8 | ## Table of Contents 9 | 10 | - [Configuration](#configuration) 11 | - [Advanced Configuration](#advanced-configuration) 12 | - [SMTP (Optional)](#smtp-optional) 13 | - [Template (Optional)](#template-optional) 14 | - [Sending OTP](#sending-otp) 15 | - [Verifying OTP](#verifying-otp) 16 | - [Get OTP](#get-otp) 17 | - [OTP Expiry Validation](#is-expired) 18 | - [Example](#example) 19 | - [Report bugs or issues](#report-bugs-or-issues) 20 | - [Contributors](#contributors) 21 | 22 | ## Configuration 23 | 24 | The simplest way to 🛠️ configure the EmailOTP package is by calling the `config` method. 25 | 26 | ```dart 27 | void main() { 28 | EmailOTP.config( 29 | appName: 'MyApp', 30 | otpType: OTPType.numeric, 31 | emailTheme: EmailTheme.v1, 32 | ); 33 | } 34 | ``` 35 | 36 | ## SMTP Configuration (Required) 37 | 38 | ⚠️ **IMPORTANT**: As of version 3.1.0, this package no longer uses a default server. You **MUST** configure your own SMTP server to send emails. 39 | 40 | ```dart 41 | EmailOTP.setSMTP( 42 | host: 'smtp.gmail.com', 43 | emailPort: EmailPort.port587, 44 | secureType: SecureType.tls, 45 | username: 'your-email@gmail.com', 46 | password: 'your-app-password', 47 | ); 48 | ``` 49 | 50 | > **Note**: For Gmail, use an [App Password](https://support.google.com/accounts/answer/185833) if 2-Step Verification is enabled. 51 | 52 | #### Advanced Configuration 53 | 54 | For more control over the OTP generation and email settings, you can pass various parameters to the `config` method. 55 | 56 | ```dart 57 | void main() { 58 | EmailOTP.config( 59 | appName: 'App Name', 60 | otpType: OTPType.numeric, 61 | expiry : 30000, 62 | emailTheme: EmailTheme.v6, 63 | appEmail: 'me@rohitchouhan.com', 64 | otpLength: 6, 65 | ); 66 | } 67 | ``` 68 | 69 | 70 | Parameters 71 | 72 | 1. `host`: The hostname of your SMTP server. 73 | 2. `emailPort`: The port number used by the SMTP server. Supported values include: 74 | - `EmailPort.port25` 75 | - `EmailPort.port465` 76 | - `EmailPort.port587` 77 | 3. `secureType:` The type of security used by the SMTP server. Supported values include: 78 | - `SecureType.none` 79 | - `SecureType.tls` 80 | - `SecureType.ssl` 81 | 4. `username`: The username for your SMTP server account. 82 | 5. `password`: The password for your SMTP server account. 83 | 84 | By configuring these parameters, you can ensure that your application is able to send OTP emails securely and efficiently. 85 | 86 | ## Themes 87 | | Theme | Theme Preview | 88 | |-----------------|----------------| 89 | | `EmailTheme.v1` | | 90 | | `EmailTheme.v2` | | 91 | | `EmailTheme.v3` | | 92 | | `EmailTheme.v4` | | 93 | | `EmailTheme.v5` | | 94 | | `EmailTheme.v6` | | 95 | 96 | 97 | ## Template (Optional) 98 | 99 | You can also customize the email 🌐 template used to send the OTP. Use the `setTemplate` method to provide your own HTML template. 100 | 101 | ```dart 102 | void main() { 103 | EmailOTP.config(); 104 | EmailOTP.setTemplate( 105 | template: ''' 106 |
107 |
108 |

{{appName}}

109 |

Your OTP is {{otp}}

110 |

This OTP is valid for 5 minutes.

111 |

Thank you for using our service.

112 |
113 |
114 | ''', 115 | ); 116 | } 117 | ``` 118 | 119 | Parameters 120 | 121 | - `template`: A string containing the HTML content of your custom email template. Use placeholders such as `{{appName}}` and `{{otp}}` to dynamically insert the application name and OTP respectively. 122 | 123 | By configuring these parameters and using a custom template, you can ensure that your OTP emails are tailored to match your application's branding and style. 124 | 125 | ## Sending OTP 126 | 127 | To 📧 send an 🔐 OTP to a user's email address, use the `sendOTP` method. This method takes the recipient's email address as a parameter. 128 | 129 | ```dart 130 | EmailOTP.sendOTP(email: emailController.text) 131 | ``` 132 | 133 | Parameters 134 | 135 | - `email`: The recipient's email address where the OTP will be sent. 136 | 137 | ## Verifying OTP 138 | 139 | To verify an 🔐 OTP entered by the user, use the `verifyOTP` method. This method takes the OTP entered by the user as a parameter and returns a boolean indicating whether the OTP is correct. 140 | 141 | ```dart 142 | EmailOTP.verifyOTP(otp: otpController.text) 143 | ``` 144 | 145 | Parameters 146 | 147 | - `otp`: The OTP entered by the user. 148 | 149 | ## Get OTP 150 | 151 | This code will print the OTP generated by the `getOTP()` method. 152 | 153 | ```dart 154 | print(EmailOTP.getOTP()); 155 | ``` 156 | 157 | ## Is Expired 158 | 159 | This method will helps you to validate your otp expiry time. 160 | 161 | ```dart 162 | print(EmailOTP.isExpired()); 163 | ``` 164 | 165 | ## Example 166 | 167 | 👉 For a complete example, refer to the [Email OTP package documentation](https://pub.dev/packages/email_otp/example). 168 | 169 | ## Report bugs or issues 170 | 171 | You are welcome to open a _[ticket](https://github.com/rohit-chouhan/email_otp/issues)_ on github if any 🐞 problems arise. New ideas are always welcome. 172 | 173 | ## Contributors 174 | 175 | Rahul Chouhan
Chouhan Rahul
176 | 177 | > Copyright © 2024 **[Rohit Chouhan](https://rohitchouhan.com)**. Licensed under the _[MIT LICENSE](https://github.com/rohit-chouhan/email_otp/blob/main/LICENSE)_ 178 | -------------------------------------------------------------------------------- /lib/email_otp.dart: -------------------------------------------------------------------------------- 1 | library email_otp; 2 | 3 | import 'dart:io'; 4 | import 'dart:math'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:mailer/mailer.dart'; 7 | import 'package:mailer/smtp_server.dart'; 8 | import 'package:http/http.dart' as http; 9 | 10 | /// Enumerations for [OTPType] 11 | enum OTPType { numeric, alpha, alphaNumeric } 12 | 13 | /// Enumerations for [EmailPort] 14 | enum SecureType { ssl, tls, none } 15 | 16 | /// Enumerations for [EmailPort] 17 | enum EmailPort { port25, port587, port465 } 18 | 19 | /// Enumerations for [EmailTheme] 20 | enum EmailTheme { v1, v2, v3, v4, v5, v6 } 21 | 22 | /// Email OTP 23 | class EmailOTP { 24 | /// OTP response 25 | static String? _otpResponse; 26 | 27 | /// App Name 28 | static String? _appName; 29 | 30 | /// Developer's Email 31 | static String? _appEmail; 32 | 33 | /// OTP Length 34 | static int? _otpLength; 35 | 36 | /// OTP Type 37 | static OTPType? _otpType; 38 | 39 | /// Expiry Time in milliseconds 40 | static int? _expiry; 41 | 42 | /// Email Theme 43 | static EmailTheme? _emailTheme; 44 | 45 | /// Email Port 46 | static EmailPort? _emailPort; 47 | 48 | /// Secure Type 49 | static SecureType? _secureType; 50 | 51 | /// SMTP Host 52 | static String? _host; 53 | 54 | /// SMTP Username 55 | static String? _username; 56 | 57 | /// SMTP Password 58 | static String? _password; 59 | 60 | /// Email Template 61 | static String? _template; 62 | 63 | /// Validate Expiry Time 64 | static bool? _isExpired; 65 | 66 | EmailOTP() { 67 | // _otpResponse = _getRandomOTP(); // Don't generate on init, generate on send or explicit call 68 | _isExpired = false; 69 | } 70 | 71 | /// Configure the EmailOTP package is by calling the [config] method 72 | static config({ 73 | String? appName, 74 | String? appEmail, 75 | int? otpLength, 76 | OTPType? otpType, 77 | int? expiry, 78 | EmailTheme? emailTheme, 79 | }) { 80 | _appName = appName ?? "Email OTP"; 81 | _appEmail = appEmail ?? "email-otp@pub.dev"; 82 | _otpLength = otpLength ?? 6; 83 | _expiry = expiry ?? 0; // No expiry by default. 84 | _otpType = otpType ?? OTPType.numeric; 85 | _emailTheme = emailTheme ?? EmailTheme.v5; 86 | } 87 | 88 | /// Use the [setSMTP] method to provide the necessary SMTP server details. 89 | static setSMTP({ 90 | required EmailPort emailPort, 91 | required SecureType secureType, 92 | required String host, 93 | required String username, 94 | required String password, 95 | }) { 96 | _emailPort = emailPort; 97 | _secureType = secureType; 98 | _host = host; 99 | _username = username; 100 | _password = password; 101 | } 102 | 103 | /// Use the [setTemplate] method to provide your own HTML template. 104 | static setTemplate({required String? template}) { 105 | _template = template; 106 | } 107 | 108 | /// To send an OTP to a user's email address, use the [sendOTP] method. 109 | static Future sendOTP({required String email}) async { 110 | if (_host == null || _username == null || _password == null) { 111 | debugPrint("❌ Error: SMTP configuration is missing. Please call setSMTP() before sending OTP."); 112 | return false; 113 | } 114 | 115 | _otpResponse = _getRandomOTP(); 116 | 117 | // Choose template 118 | String htmlBody; 119 | try { 120 | if (_template != null) { 121 | htmlBody = _template!; 122 | } else if (_emailTheme != null) { 123 | htmlBody = await _getThemeHtml(_emailTheme!); 124 | } else { 125 | htmlBody = _getDefaultTheme(); 126 | } 127 | } catch (e) { 128 | debugPrint("⚠️ Error loading theme: $e. Using default theme."); 129 | htmlBody = _getDefaultTheme(); 130 | } 131 | 132 | // Replace placeholders 133 | htmlBody = htmlBody.replaceAll('{{appName}}', _appName ?? "App Name") 134 | .replaceAll('{{otp}}', _otpResponse!); 135 | 136 | // SMTP Server Config 137 | int port = 587; // default 138 | if (_emailPort == EmailPort.port25) port = 25; 139 | if (_emailPort == EmailPort.port465) port = 465; 140 | if (_emailPort == EmailPort.port587) port = 587; 141 | 142 | final smtpServer = SmtpServer(_host!, 143 | port: port, 144 | username: _username, 145 | password: _password, 146 | ssl: _secureType == SecureType.ssl, 147 | allowInsecure: _secureType == SecureType.none || _secureType == null, 148 | ignoreBadCertificate: false, 149 | ); 150 | 151 | final message = Message() 152 | ..from = Address(_appEmail ?? _username!, _appName) 153 | ..recipients.add(email) 154 | ..subject = 'Verification Code - ${_appName ?? "App Name"}' 155 | ..html = htmlBody; 156 | 157 | try { 158 | final verifySend = await send(message, smtpServer); 159 | debugPrint("✅️ OTP Sent to Email 📧 Successfully: ${verifySend.toString()}"); 160 | 161 | if (_expiry != null && _expiry! > 0) { 162 | var rand = _getRandomOTP(); 163 | _reassignOtpAfterDelay( 164 | Duration(milliseconds: _expiry!), rand.toString()); 165 | } 166 | return true; 167 | } on MailerException catch (e) { 168 | debugPrint("❌ Mailer Error: ${e.toString()}"); 169 | for (var p in e.problems) { 170 | debugPrint('Problem: ${p.code}: ${p.msg}'); 171 | } 172 | return false; 173 | } on SocketException catch (e) { 174 | debugPrint("❌ Network Error: Connection to SMTP server failed. Check host, port, and internet connection."); 175 | debugPrint("Details: ${e.message}"); 176 | return false; 177 | } on TlsException catch (e) { 178 | debugPrint("❌ Security Error: TLS/SSL handshake failed. Check your security settings (SSL vs TLS)."); 179 | debugPrint("Details: ${e.message}"); 180 | return false; 181 | } catch (e) { 182 | debugPrint("❌ Unexpected Error: $e"); 183 | return false; 184 | } 185 | } 186 | 187 | /// Get Sent OTP, use the [getOTP] method. 188 | static String? getOTP() { 189 | debugPrint("Retrieved OTP: $_otpResponse"); 190 | return _otpResponse; 191 | } 192 | 193 | /// To verify an OTP entered by the user, use the [verifyOTP] method. 194 | static bool verifyOTP({required String otp}) { 195 | if (_otpResponse == otp) { 196 | debugPrint("✅️ OTP 🔑 Validate Successfully"); 197 | _expiry = null; // Expiry time reset after successful verification. 198 | return true; 199 | } else { 200 | debugPrint("❌ Invalid 🔑 OTP"); 201 | return false; 202 | } 203 | } 204 | 205 | /// To check if the OTP has expired, use the [isOtpExpired] method. 206 | static bool isOtpExpired() { 207 | return _isExpired ?? false; 208 | } 209 | 210 | static void _reassignOtpAfterDelay(Duration delay, String newValue) { 211 | Future.delayed(delay, () { 212 | _otpResponse = newValue; 213 | _isExpired = true; 214 | debugPrint("OTP reassigned: $_otpResponse"); 215 | }); 216 | } 217 | 218 | static String _getRandomOTP() { 219 | int length = _otpLength ?? 6; 220 | if(_otpType == OTPType.numeric) { 221 | int min = pow(10, length - 1).toInt(); 222 | int max = pow(10, length).toInt() - 1; 223 | return (Random().nextInt(max - min) + min).toString(); 224 | } else if (_otpType == OTPType.alpha) { 225 | const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 226 | return List.generate(length, (index) => chars[Random().nextInt(chars.length)]).join(); 227 | } else { 228 | const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; 229 | return List.generate(length, (index) => chars[Random().nextInt(chars.length)]).join(); 230 | } 231 | } 232 | 233 | static Future _getThemeHtml(EmailTheme theme) async { 234 | // Fetch the HTML template corresponding to the theme (e.g., v1.html, v2.html) 235 | // from the GitHub repository via jsdelivr. 236 | String themeName = theme.name; // v1, v2, etc. 237 | String url = "https://cdn.jsdelivr.net/gh/rohit-chouhan/email_otp@main/templates/$themeName.html"; 238 | try { 239 | final response = await http.get(Uri.parse(url)); 240 | if (response.statusCode == 200) { 241 | return response.body; 242 | // The calling function (sendOTP) will replace {{appName}} and {{otp}} placeholders 243 | // in this returned HTML. 244 | } else { 245 | debugPrint("⚠️ Failed to fetch template from $url (Status: ${response.statusCode}). Using fallback."); 246 | return _getDefaultTheme(theme); 247 | } 248 | } catch (e) { 249 | debugPrint("⚠️ Error fetching template: $e. Using fallback."); 250 | return _getDefaultTheme(theme); 251 | } 252 | } 253 | 254 | static String _getDefaultTheme([EmailTheme? theme]) { 255 | String color = "#3366FF"; // v1/default color 256 | if (theme != null) { 257 | switch(theme) { 258 | case EmailTheme.v1: color = "#FF5733"; break; 259 | case EmailTheme.v2: color = "#33FF57"; break; 260 | case EmailTheme.v3: color = "#3357FF"; break; 261 | case EmailTheme.v4: color = "#FF33A1"; break; 262 | case EmailTheme.v5: color = "#33FFF6"; break; 263 | case EmailTheme.v6: color = "#F6FF33"; break; 264 | } 265 | } 266 | 267 | return """ 268 | 269 | 270 | 271 | 278 | 279 | 280 |
281 |
282 |

Verification Code

283 |
284 |
285 |

Hello,

286 |

Your verification code for {{appName}} is:

287 |
{{otp}}
288 |

Please do not share this code with anyone.

289 |
290 | 293 |
294 | 295 | 296 | """; 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /templates/v1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 100 | 101 | 102 | 104 | 107 | 110 | 111 | 112 | 203 | 204 | 205 | 206 | 207 | 208 | --------------------------------------------------------------------------------