diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8a9c1ce..2d09490 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.3
+
+- Implemented mail
+
## 0.1.2
- Implemented multi-isolate server
diff --git a/lib/src/application.dart b/lib/src/application.dart
index ede3a7d..b1be725 100644
--- a/lib/src/application.dart
+++ b/lib/src/application.dart
@@ -21,7 +21,7 @@ class Application extends Container {
server = BaseHttpServer(config: config);
- if (config['isolate']) {
+ if (config['isolate'] != null && config['isolate']) {
server.spawnIsolates(config['isolateCount'] ?? 1);
} else {
server.startServer();
diff --git a/lib/src/mail/content.dart b/lib/src/mail/content.dart
new file mode 100644
index 0000000..4d0baaf
--- /dev/null
+++ b/lib/src/mail/content.dart
@@ -0,0 +1,12 @@
+class Content {
+ /// The Blade view that represents the text version of the message.
+ final String? text;
+
+ /// The Blade view that should be rendered for the mailable.
+ final String? html;
+
+ const Content({
+ this.text,
+ this.html,
+ });
+}
diff --git a/lib/src/mail/envelope.dart b/lib/src/mail/envelope.dart
new file mode 100644
index 0000000..227c483
--- /dev/null
+++ b/lib/src/mail/envelope.dart
@@ -0,0 +1,26 @@
+import 'package:mailer/mailer.dart';
+
+class Envelope {
+ ///The address sending the message.
+ final Address? from;
+
+ /// The recipients of the message.
+ final List
to;
+
+ /// The recipients receiving a copy of the message.
+ final List? cc;
+
+ /// The recipients receiving a blind copy of the message.
+ final List? bcc;
+
+ /// The subject of the message.
+ final String subject;
+
+ Envelope({
+ this.from,
+ required this.to,
+ required this.subject,
+ this.cc,
+ this.bcc,
+ });
+}
diff --git a/lib/src/mail/mail.dart b/lib/src/mail/mail.dart
new file mode 100644
index 0000000..5df3079
--- /dev/null
+++ b/lib/src/mail/mail.dart
@@ -0,0 +1,11 @@
+import 'package:mailer/mailer.dart';
+
+import 'content.dart';
+import 'envelope.dart';
+
+abstract class Mail {
+ const Mail();
+ Content content();
+ Envelope envelope();
+ List? attachments();
+}
diff --git a/lib/src/mail/mailable.dart b/lib/src/mail/mailable.dart
new file mode 100644
index 0000000..e4d7bb2
--- /dev/null
+++ b/lib/src/mail/mailable.dart
@@ -0,0 +1,101 @@
+import 'package:mailer/mailer.dart' as mailer;
+import 'package:mailer/smtp_server.dart';
+import 'package:meta/meta.dart';
+import 'package:vania/src/mail/mail.dart';
+import 'package:vania/vania.dart';
+
+@immutable
+class Mailable implements Mail {
+ const Mailable();
+
+ SmtpServer _setupSmtpServer() {
+ switch (Config().get('mail')['driver']) {
+ case 'gmail':
+ return gmail(
+ Config().get('mail')['username'], Config().get('mail')['password']);
+ case 'gmailSaslXoauth2':
+ return gmailSaslXoauth2(Config().get('mail')['username'],
+ Config().get('mail')['accessToken']);
+ case 'gmailRelaySaslXoauth2':
+ return gmail(Config().get('mail')['username'],
+ Config().get('mail')['accessToken']);
+ case 'hotmail':
+ return hotmail(
+ Config().get('mail')['username'], Config().get('mail')['password']);
+ case 'mailgun':
+ return mailgun(
+ Config().get('mail')['username'], Config().get('mail')['password']);
+ case 'qq':
+ return qq(
+ Config().get('mail')['username'], Config().get('mail')['password']);
+ case 'yahoo':
+ return yahoo(
+ Config().get('mail')['username'], Config().get('mail')['password']);
+ case 'yandex':
+ return yandex(
+ Config().get('mail')['username'], Config().get('mail')['password']);
+ default:
+ return SmtpServer(
+ Config().get('mail')['host'] ?? '',
+ username: Config().get('mail')['username'] ?? '',
+ password: Config().get('mail')['password'] ?? '',
+ port: Config().get('mail')['port'],
+ ssl: Config().get('mail')['encryption'] == 'ssl',
+ ignoreBadCertificate:
+ Config().get('mail')['ignoreBadCertificate'] ?? true,
+ );
+ }
+ }
+
+ Future send() async {
+ final message = mailer.Message();
+
+ message.from = envelope().from ??
+ Address(
+ Config().get('mail')['from_address'],
+ Config().get('mail')['from_name'],
+ );
+ message.recipients.addAll(envelope().to);
+
+ if (envelope().cc != null) {
+ message.ccRecipients.addAll(envelope().cc!);
+ }
+
+ if (envelope().bcc != null) {
+ message.ccRecipients.addAll(envelope().bcc!);
+ }
+
+ message.subject = envelope().subject;
+ message.text = content().text;
+ message.html = content().html;
+
+ if (attachments() != null) {
+ message.attachments.addAll(attachments()!);
+ }
+
+ try {
+ await mailer.send(message, _setupSmtpServer());
+ } catch (e) {
+ print('Failed to send email: $e');
+ rethrow;
+ }
+ }
+
+ @mustBeOverridden
+ @override
+ List? attachments() {
+ throw UnimplementedError();
+ }
+
+ @mustBeOverridden
+ @override
+ Content content() {
+ throw UnimplementedError();
+ }
+
+ @mustBeOverridden
+ @override
+ Envelope envelope() {
+ throw UnimplementedError();
+ }
+}
diff --git a/lib/src/route/router.dart b/lib/src/route/router.dart
index 83cab39..5b4d4be 100644
--- a/lib/src/route/router.dart
+++ b/lib/src/route/router.dart
@@ -58,11 +58,11 @@ class Router {
return this;
}
- Router prefix([String? prifix]) {
- if (prifix != null) {
+ Router prefix([String? prefix]) {
+ if (prefix != null) {
String basePath = _routes.last.path;
_routes.last.path =
- prifix.endsWith("/") ? "$prifix$basePath" : "$prifix/$basePath";
+ prifix.endsWith("/") ? "$prefix$basePath" : "$prefix/$basePath";
}
return this;
}
diff --git a/lib/src/storage/local_storage.dart b/lib/src/storage/local_storage.dart
index 83116d9..3df7d30 100644
--- a/lib/src/storage/local_storage.dart
+++ b/lib/src/storage/local_storage.dart
@@ -44,4 +44,7 @@ class LocalStorage implements StorageDriver {
await file.writeAsBytes(bytes);
return file.path.replaceFirst(storagePath, '');
}
+
+ @override
+ String fullPath(String file) => "$storagePath/$file";
}
diff --git a/lib/src/storage/storage_driver.dart b/lib/src/storage/storage_driver.dart
index 736fa7c..011c113 100644
--- a/lib/src/storage/storage_driver.dart
+++ b/lib/src/storage/storage_driver.dart
@@ -2,13 +2,15 @@ import 'dart:typed_data';
abstract class StorageDriver {
Future put(
- String filePath,
+ String fileName,
List bytes,
);
- Future get(String filepath);
+ Future get(String fileName);
- Future exists(String filepath);
+ String fullPath(String file);
- Future delete(String filepath);
+ Future exists(String fileName);
+
+ Future delete(String fileName);
}
diff --git a/lib/src/utils/helper.dart b/lib/src/utils/helper.dart
new file mode 100644
index 0000000..a554238
--- /dev/null
+++ b/lib/src/utils/helper.dart
@@ -0,0 +1,5 @@
+import 'dart:io';
+
+String storagePath(String file) => '${Directory.current.path}/storage/$file';
+
+String publicPath(String file) => '${Directory.current.path}/public/$file';
diff --git a/lib/vania.dart b/lib/vania.dart
index 8c7c6cc..3dac533 100644
--- a/lib/vania.dart
+++ b/lib/vania.dart
@@ -42,3 +42,11 @@ export 'package:eloquent/src/query/query_builder.dart';
export 'src/authentication/authentication.dart';
export 'src/authentication/authenticate.dart';
export 'src/cryptographic/hash.dart';
+
+export 'src/mail/mailable.dart';
+export 'src/mail/content.dart';
+export 'src/mail/envelope.dart';
+export 'package:mailer/src/entities/address.dart';
+export 'package:mailer/src/entities/attachment.dart';
+
+export 'src/utils/helper.dart';
diff --git a/pubspec.yaml b/pubspec.yaml
index ff67064..5f6d7f7 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: vania
description: Fast, simple, and powerful backend framework for Dart built with ❤️
-version: 0.1.2
+version: 0.1.3
homepage: https://vdart.dev
repository: https://github.com/vania-dart/framework
issue_tracker: https://github.com/vania-dart/framework/issues
@@ -19,6 +19,7 @@ dependencies:
crypto: ^3.0.3
dart_jsonwebtoken: ^2.13.0
eloquent: ^3.0.0
+ mailer: ^6.1.0
meta: ^1.12.0
mime: ^1.0.5
path: ^1.9.0
@@ -29,5 +30,5 @@ dependencies:
dev_dependencies:
lints: ^3.0.0
test: ^1.25.2
- http: ^1.2.0
+ http: ^1.2.1
http_parser: ^4.0.2