├── .env.example ├── src-tauri ├── src │ ├── build.rs │ ├── window.rs │ ├── main.rs │ ├── forward.rs │ └── smtp.rs ├── icons │ ├── 32x32.png │ ├── icon.icns │ ├── icon.ico │ ├── icon.png │ ├── 128x128.png │ ├── 128x128@2x.png │ ├── StoreLogo.png │ ├── Square30x30Logo.png │ ├── Square44x44Logo.png │ ├── Square71x71Logo.png │ ├── Square89x89Logo.png │ ├── Square107x107Logo.png │ ├── Square142x142Logo.png │ ├── Square150x150Logo.png │ ├── Square284x284Logo.png │ └── Square310x310Logo.png ├── .gitignore ├── rustfmt.toml ├── Cargo.toml ├── tauri.conf.json └── Cargo.lock ├── public ├── favicon.ico ├── robots.txt └── index.html ├── src ├── styles │ ├── tailwind.base │ ├── main.css │ └── tailwind.css ├── store │ ├── store.js │ ├── mailboxReducer.js │ └── settingReducer.js ├── index.js ├── App.js ├── components │ ├── MailContent.js │ └── Sidebar.js └── screens │ ├── Mailbox.js │ └── Settings.js ├── screenshots ├── setting.png ├── html-mail.png └── spam-score.png ├── docs ├── _config.yml └── index.md ├── .github ├── ISSUE_TEMPLATE │ ├── custom.md │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── publish.yml ├── config-overrides.js ├── .gitignore ├── tailwind.config.js ├── LICENSE ├── package.json └── README.md /.env.example: -------------------------------------------------------------------------------- 1 | BROWSER=none 2 | NODE_OPTIONS=--openssl-legacy-provider -------------------------------------------------------------------------------- /src-tauri/src/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/styles/tailwind.base: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /screenshots/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/screenshots/setting.png -------------------------------------------------------------------------------- /screenshots/html-mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/screenshots/html-mail.png -------------------------------------------------------------------------------- /screenshots/spam-score.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/screenshots/spam-score.png -------------------------------------------------------------------------------- /src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | WixTools 5 | -------------------------------------------------------------------------------- /src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samirdjelal/mail-dev/HEAD/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | show_downloads: true 3 | title: Mail-Dev 4 | description: Local SMTP Server For Email Testing/Debugging 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /config-overrides.js: -------------------------------------------------------------------------------- 1 | const {override, addExternalBabelPlugin} = require("customize-cra"); 2 | module.exports = override( 3 | addExternalBabelPlugin(["@babel/plugin-proposal-nullish-coalescing-operator"]) 4 | ); -------------------------------------------------------------------------------- /src/store/store.js: -------------------------------------------------------------------------------- 1 | import {configureStore} from "@reduxjs/toolkit"; 2 | import settingReducer from "./settingReducer"; 3 | import mailboxReducer from "./mailboxReducer"; 4 | 5 | export default configureStore({ 6 | reducer: { 7 | setting: settingReducer, 8 | mailbox: mailboxReducer, 9 | } 10 | }) -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
23 |
25 |
27 |
28 | ## Requirement:
29 | - Tauri CLI
30 | - NodeJS (npm/yarn)
31 |
32 | ### Dev
33 | ```text
34 | npm install
35 | npm run tailwind:dev
36 | npm run tauri dev
37 | ```
38 |
39 | ### Build
40 | ```text
41 | npm install
42 | npm run tailwind:dev
43 | npm run tauri build
44 | ```
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mail-Dev
2 |
3 |
26 |
28 |
30 |
31 | ## Requirement:
32 | - Tauri CLI
33 | - NodeJS (npm/yarn)
34 |
35 | ### Dev
36 | ```text
37 | npm install
38 | npm run tailwind:dev
39 | npm run tauri dev
40 | ```
41 |
42 | ### Build
43 | ```text
44 | npm install
45 | npm run tailwind:dev
46 | npm run tauri build
47 | ```
48 |
--------------------------------------------------------------------------------
/src/store/mailboxReducer.js:
--------------------------------------------------------------------------------
1 | import {createSlice} from "@reduxjs/toolkit";
2 |
3 | const mailboxState = createSlice({
4 | name: 'mailbox',
5 | initialState: {
6 | mails: [],
7 | mailIndex: null,
8 | mail: {}
9 | },
10 | reducers: {
11 | clearMails: (state, _action) => ({...state, mails: [], mailIndex: null, mail: {}}),
12 | addMail: (state, action) => {
13 | const arr = action.payload.to.match(/^<(.+?)>$/);
14 | if (arr) action.payload.to = arr[1];
15 | return {...state, mails: [...state.mails, {...action.payload, key: Math.random().toString(), seen: false, spam_score: "", spam_rules: []}]};
16 | },
17 | setMailIndex: (state, action) => {
18 | let mail_object = {};
19 | let copy = state.mails.map(mail => {
20 | if (mail.key === action.payload) {
21 | mail_object = mail;
22 | return {...mail, seen: true};
23 | }
24 | return {...mail};
25 | })
26 | return {...state, mails: copy, mailIndex: action.payload, mail: mail_object};
27 | },
28 | setSpamScore: (state, action) => {
29 | console.log(action.payload)
30 | let mail_object = {};
31 | let copy = state.mails.map(mail => {
32 | if (mail.key === action.payload.key) {
33 | return mail_object = {...mail, seen: true, spam_score: action.payload.spam_score, spam_rules: action.payload.spam_rules};
34 | }
35 | return {...mail};
36 | })
37 | return {...state, mails: copy, mail: mail_object};
38 | },
39 | deleteMail: (state, action) => {
40 | let copy = state.mails.filter(mail => mail.key !== action.payload)
41 | return {...state, mails: copy, mailIndex: null, mail: {}};
42 | },
43 | }
44 | })
45 |
46 | export const {
47 | clearMails,
48 | addMail,
49 | setMailIndex,
50 | setSpamScore,
51 | deleteMail,
52 | } = mailboxState.actions;
53 |
54 |
55 | export default mailboxState.reducer
--------------------------------------------------------------------------------
/src-tauri/tauri.conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "package": {
3 | "productName": "mail-dev",
4 | "version": "0.7.1"
5 | },
6 | "build": {
7 | "distDir": "../build",
8 | "devPath": "http://localhost:3000",
9 | "beforeDevCommand": "npm run dev",
10 | "beforeBuildCommand": "npm run build"
11 | },
12 | "tauri": {
13 | "bundle": {
14 | "active": true,
15 | "targets": "all",
16 | "identifier": "com.samirdjelal.mail-dev",
17 | "icon": [
18 | "icons/32x32.png",
19 | "icons/128x128.png",
20 | "icons/128x128@2x.png",
21 | "icons/icon.icns",
22 | "icons/icon.ico"
23 | ],
24 | "resources": [],
25 | "externalBin": [],
26 | "copyright": "",
27 | "category": "DeveloperTool",
28 | "shortDescription": "",
29 | "longDescription": "",
30 | "deb": {
31 | "depends": []
32 | },
33 | "macOS": {
34 | "frameworks": [],
35 | "minimumSystemVersion": "",
36 | "exceptionDomain": "",
37 | "signingIdentity": null,
38 | "entitlements": null
39 | },
40 | "windows": {
41 | "certificateThumbprint": null,
42 | "digestAlgorithm": "sha256",
43 | "timestampUrl": ""
44 | }
45 | },
46 | "updater": {
47 | "active": false
48 | },
49 | "allowlist": {
50 | "all": true,
51 | "http": {
52 | "all": true,
53 | "request": true,
54 | "scope": [
55 | "https://spamcheck.postmarkapp.com/*"
56 | ]
57 | }
58 | },
59 | "windows": [
60 | {
61 | "title": "Mail Dev",
62 | "width": 1100,
63 | "height": 700,
64 | "minWidth": 950,
65 | "minHeight": 600,
66 | "resizable": true,
67 | "fullscreen": false,
68 | "center": true
69 | }
70 | ],
71 | "macOSPrivateApi": true,
72 | "security": {
73 | "csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'"
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/src/store/settingReducer.js:
--------------------------------------------------------------------------------
1 | import {createSlice} from "@reduxjs/toolkit";
2 |
3 | const settingState = createSlice({
4 | name: 'setting',
5 | initialState: {
6 | srvStatus: false,
7 | srvErrorMessage: "",
8 | framework: "Laravel",
9 | ipAddress: "127.0.0.1",
10 | port: 2525,
11 | spamChecking: true,
12 |
13 | forwardEmailHost: "smtp.gmail.com",
14 | forwardEmailPort: "587",
15 | forwardEmailUsername: "",
16 | forwardEmailPassword: "",
17 | forwardEnabled: false,
18 |
19 | useNotification: true,
20 |
21 | },
22 | reducers: {
23 | setSrvStatus: (state, action) => ({...state, srvStatus: action.payload}),
24 | setSrvResponseMessage: (state, action) => ({...state, srvResponseMessage: action.payload}),
25 | setFramework: (state, action) => ({...state, framework: action.payload}),
26 | setIpAddress: (state, action) => ({...state, ipAddress: action.payload}),
27 | setPort: (state, action) => ({...state, port: action.payload}),
28 | setSpamChecking: (state, action) => ({...state, spamChecking: action.payload}),
29 |
30 | setForwardEmailHost: (state, action) => ({...state, forwardEmailHost: action.payload}),
31 | setForwardEmailPort: (state, action) => ({...state, forwardEmailPort: action.payload}),
32 | setForwardEmailUsername: (state, action) => ({...state, forwardEmailUsername: action.payload}),
33 | setForwardEmailPassword: (state, action) => ({...state, forwardEmailPassword: action.payload}),
34 | setForwardEnabled: (state, action) => ({...state, forwardEnabled: action.payload}),
35 |
36 | setUseNotification: (state, action) => ({...state, useNotification: action.payload}),
37 |
38 | }
39 | })
40 |
41 | export const {
42 | setSrvStatus,
43 | setSrvResponseMessage,
44 | setFramework,
45 | setIpAddress,
46 | setPort,
47 | setForwardEmailHost,
48 | setForwardEmailPort,
49 | setForwardEmailUsername,
50 | setForwardEmailPassword,
51 | setForwardEnabled,
52 | setUseNotification,
53 | } = settingState.actions;
54 |
55 |
56 | export default settingState.reducer
--------------------------------------------------------------------------------
/src-tauri/src/forward.rs:
--------------------------------------------------------------------------------
1 | use lettre::message::Mailbox;
2 | use lettre::transport::smtp::authentication::Credentials;
3 | use lettre::transport::smtp::client::{Tls, TlsParametersBuilder};
4 | use lettre::{Address, Message, SmtpTransport, Transport};
5 |
6 | #[tauri::command]
7 | pub async fn forward_mail(
8 | host: OptionThe lower your score, the more likely your email is going to be received in your subscribers' inboxes.
34 || Score | 39 |Description | 40 |
|---|---|
| {rule.score} | 46 |{rule.description} | 47 |
135 | If you are using Vagrant/Homestead, use "10.0.2.2" as your SMTP-Host.
136 | For Docker, use "host.docker.internal" as your SMTP-Host.
137 |
141 | Use these configuration values in your Laravel applications .env file: 142 |
143 | 144 |
146 | {`MAIL_MAILER=smtp\nMAIL_HOST=${this.props.ipAddress}\nMAIL_PORT=${this.props.port}\nMAIL_USERNAME=null\nMAIL_PASSWORD=null\nMAIL_ENCRYPTION=null`}
147 |
148 |
149 |
151 | {`MAIL_DRIVER=smtp\nMAIL_HOST=${this.props.ipAddress}\nMAIL_PORT=${this.props.port}\nMAIL_USERNAME=null\nMAIL_PASSWORD=null\nMAIL_ENCRYPTION=null`}
152 |
153 |
157 | Symfony uses SwiftMailerBundle to send emails. You can find more information on how to send email on.
158 | To get started you need to modify .env file in your project directory and set MAILER_URL value:
159 |
162 | {`MAILER_URL=smtp://${this.props.ipAddress}:${this.props.port}?encryption=null&auth_mode=null`}
163 |
164 |
165 |
166 | 170 | You can configure your WordPress site to send mails to Mail-Dev by using : 171 |
172 | 173 |
174 | {`function mail_dev($phpmailer) {\n\t$phpmailer->isSMTP();\n\t$phpmailer->Host = '${this.props.ipAddress}';\n\t$phpmailer->SMTPAuth = false;\n\t$phpmailer->Port = ${this.props.port};\n}\n\nadd_action('phpmailer_init', 'mail_dev');`}
175 |
176 |
180 | You can find documentation for sending emails using SMTP in Yii Framework here.
181 | In your config file add:
182 |
185 | {`'components' => [\n\t'mailer' => [\n\t\t'class' => 'yii\\swiftmailer\\Mailer',\n\t\t'enableSwiftMailerLogging' => true,\n\t\t'transport' => [\n\t\t\t'class' => 'Swift_SmtpTransport',\n\t\t\t"host" => '${this.props.ipAddress}',\n\t\t\t"port" => ${this.props.port},\n\t\t],\n\t],\n],`}
186 |
187 |
188 |
192 | Nodemailer is an easy to use module to send e-mails with Node.JS:
193 |
196 | {`let transport = nodemailer.createTransport({\n\thost: "${this.props.ipAddress}",\n\tport: ${this.props.port},\n});`}
197 |
198 | 202 | In config/environments/*.rb specify ActionMailer defaults for your development or staging servers: 203 |
204 | 205 |
206 | {`config.action_mailer.delivery_method = :smtp \nconfig.action_mailer.smtp_settings = {\n\t:address => '${this.props.ipAddress}',\n\t:domain => '${this.props.ipAddress}',\n\t:port => '${this.props.port}',\n}`}
207 |
208 |
209 | 213 | Sending email using net/smtp from Ruby stdlib: 214 |
215 | 216 |
217 | {`require 'net/smtp'\n\nmessage = <<-END.split("\n").map!(&:strip).join("\n")\nFrom: Private Person \nTo: A Test User \nSubject: MAIL-DEV!\n\nThis is a test e-mail message from MAIL-DEV.\nEND\n\nNet::SMTP.start('${this.props.ipAddress}',\n ${this.props.port},\n '${this.props.ipAddress}') do |smtp|\nsmtp.send_message message, 'from@${this.props.ipAddress}',\n 'to@${this.props.ipAddress}'\nend`}
218 |
219 |
220 |