diff --git a/.gitignore b/.gitignore
index 2acd9c2..4514284 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,2 @@
-logs
-node_modules/
-.vagrant
.idea
-target
+*.patch
\ No newline at end of file
diff --git a/readme.md b/readme.md
index cfb8556..63f5d89 100644
--- a/readme.md
+++ b/readme.md
@@ -3,9 +3,9 @@
[](https://gitter.im/synox/disposable-mailbox?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Goals:
- * easy to use: generate random name or use custom name, auto refresh
- * easy to host: just php5 + imap extension
- * easy to install: just copy some files
+ * easy to use: random or custom name, auto refresh
+ * easy to host: just php5 with imap extension, catch-all mailbox
+ * easy to install: copy-paste and imap config
* minimal code base: minimal features and complexity
|  |
@@ -19,11 +19,11 @@
* Licence: 
disposable-mailbox by github:synox is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
-## Webserver requirements
+## Requirements
-* php >=5.3.0
-* [imap extension](http://php.net/manual/book.imap.php)
-* apache 2 (let me know how it works on nginx!)
+* apache 2 webserver with php >=5.3.0 (let me know how it works on nginx!)
+* php [imap extension](http://php.net/manual/book.imap.php)
+* IMAP account and a domain with catch-all configuration. (all mails go to one mailbox).
## Installation
@@ -32,9 +32,10 @@
2. download a [release](https://github.com/synox/disposable-mailbox/releases) or clone this repository
-3. copy the `src` directory to your web server.
+3. copy the files in the `src` directory to your web server (not the whole repo!).
4. rename `config.sample.php` to `config.php` and apply the imap settings. Move `config.php` to a safe location outside the `public_html`.
5. edit `backend.php` and set the new path to `config.php`.
+6. open it in your browser, check your php error log for messages.
## Build it yourself
diff --git a/screenshot.png b/screenshot.png
index 000b879..baf5f2d 100644
Binary files a/screenshot.png and b/screenshot.png differ
diff --git a/src/backend.php b/src/backend.php
index 2212b57..fb67dd1 100644
--- a/src/backend.php
+++ b/src/backend.php
@@ -21,13 +21,20 @@ function error($status, $text) {
}
/**
- * print all mails for the given $user as a json string.
+ * print all mails for the given $user.
* @param $username string username
* @param $address string email address
*/
function print_emails($username, $address) {
- $mail_ids = _search_mails($address);
+ global $mailbox;
+
+ // Search for mails with the recipient $address in TO or CC.
+ $mailsIdsTo = imap_sort($mailbox->getImapStream(), SORTARRIVAL, true, SE_UID, 'TO "' . $address . '"');
+ $mailsIdsCc = imap_sort($mailbox->getImapStream(), SORTARRIVAL, true, SE_UID, 'CC "' . $address . '"');
+ $mail_ids = array_merge($mailsIdsTo, $mailsIdsCc);
+
$emails = _load_emails($mail_ids, $address);
+ header('Content-type: application/json');
print(json_encode(array("mails" => $emails, 'username' => $username, 'address' => $address)));
}
@@ -35,25 +42,59 @@ function print_emails($username, $address) {
/**
* deletes emails by id and username. The $address must match the recipient in the email.
*
- * @param $mailid integer imap email id (integer)
+ * @param $mailid integer imap email id
* @param $address string email address
* @internal param the $username matching username
*/
function delete_email($mailid, $address) {
global $mailbox;
- // in order to avoid https://www.owasp.org/index.php/Top_10_2013-A4-Insecure_Direct_Object_References
- // the recipient in the email has to match the $address.
- $emails = _load_emails(array($mailid), $address);
- if (count($emails) === 1) {
+ if (_load_one_email($mailid, $address) !== null) {
$mailbox->deleteMail($mailid);
$mailbox->expungeDeletedMails();
+ header('Content-type: application/json');
print(json_encode(array("success" => true)));
} else {
error(404, 'delete error: invalid username/mailid combination');
}
}
+/**
+ * download email by id and username. The $address must match the recipient in the email.
+ *
+ * @param $mailid integer imap email id
+ * @param $address string email address
+ * @internal param the $username matching username
+ */
+
+function download_email($mailid, $address) {
+ global $mailbox;
+
+ if (_load_one_email($mailid, $address) !== null) {
+ header("Content-Type: message/rfc822; charset=utf-8");
+ header("Content-Disposition: attachment; filename=\"$address-$mailid.eml\"");
+
+ $headers = imap_fetchheader($mailbox->getImapStream(), $mailid, FT_UID);
+ $body = imap_body($mailbox->getImapStream(), $mailid, FT_UID);
+ print ($headers . "\n" . $body);
+ } else {
+ error(404, 'download error: invalid username/mailid combination');
+ }
+}
+
+/**
+ * Load exactly one email, the $address in TO or CC has to match.
+ * @param $mailid integer
+ * @param $address String address
+ * @return email or null
+ */
+function _load_one_email($mailid, $address) {
+ // in order to avoid https://www.owasp.org/index.php/Top_10_2013-A4-Insecure_Direct_Object_References
+ // the recipient in the email has to match the $address.
+ $emails = _load_emails(array($mailid), $address);
+ return count($emails) === 1 ? $emails[0] : null;
+}
+
/**
* Load emails using the $mail_ids, the mails have to match the $address in TO or CC.
* @param $mail_ids array of integer ids
@@ -67,29 +108,13 @@ function _load_emails($mail_ids, $address) {
foreach ($mail_ids as $id) {
$mail = $mailbox->getMail($id);
// imap_search also returns partials matches. The mails have to be filtered again:
- if (!array_key_exists($address, $mail->to) && !array_key_exists($address, $mail->cc)) {
- continue;
+ if (array_key_exists($address, $mail->to) || array_key_exists($address, $mail->cc)) {
+ $emails[] = $mail;
}
- $emails[] = $mail;
}
return $emails;
}
-
-/**
- * Search for mails with the recipient $address.
- * @param $address string address that has to match TO or CC.
- * @return array email ids
- */
-function _search_mails($address) {
- global $mailbox;
- $filterTO = 'TO "' . $address . '"';
- $filterCC = 'CC "' . $address . '"';
- $mailsIdsTo = imap_sort($mailbox->getImapStream(), SORTARRIVAL, true, SE_UID, $filterTO);
- $mailsIdsCc = imap_sort($mailbox->getImapStream(), SORTARRIVAL, true, SE_UID, $filterCC);
- return array_merge($mailsIdsTo, $mailsIdsCc);
-}
-
/**
* Remove illegal characters from username and remove everything after the @-sign. You may extend it if your server supports them.
* @param $username
@@ -98,34 +123,27 @@ function _search_mails($address) {
function _clean_username($username) {
$username = strtolower($username);
$username = preg_replace('/@.*$/', "", $username); // remove part after @
- $username = preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
- return $username;
+ return preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
}
-
/**
* deletes messages older than X days.
*/
function delete_old_messages() {
- global $mailbox;
+ global $mailbox, $config;
- $date = date('d-M-Y', strtotime('30 days ago'));
- $ids = $mailbox->searchMailbox('BEFORE ' . $date);
+ $ids = $mailbox->searchMailbox('BEFORE ' . date('d-M-Y', strtotime($config['delete_messages_older_than'])));
foreach ($ids as $id) {
$mailbox->deleteMail($id);
}
$mailbox->expungeDeletedMails();
}
-
-header('Content-type: application/json');
-
// Never cache requests:
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
-
if (isset($_GET['username'])) {
// perform common validation:
$username = _clean_username($_GET['username']);
@@ -135,7 +153,9 @@ if (isset($_GET['username'])) {
$address = $username . "@" . $config['mailHostname'];
// simple router:
- if (isset($_GET['delete_email_id'])) {
+ if (isset($_GET['download_email_id'])) {
+ download_email($_GET['download_email_id'], $address);
+ } else if (isset($_GET['delete_email_id'])) {
delete_email($_GET['delete_email_id'], $address);
} else {
print_emails($username, $address);
diff --git a/src/client-libs/index.js b/src/client-libs/index.js
index 4925f2b..e3f30f0 100644
--- a/src/client-libs/index.js
+++ b/src/client-libs/index.js
@@ -39,6 +39,8 @@ app.filter("autolink", function () {
app.controller('MailboxController', ["$interval", "$http", "$log", function ($interval, $http, $log) {
var self = this;
+ self.backend_url = backend_url;
+
self.updateUsername = function (username) {
username = username.replace(/[@].*$/, ''); // remove part after "@"
if (self.username !== username) {
@@ -50,8 +52,7 @@ app.controller('MailboxController', ["$interval", "$http", "$log", function ($in
self.address = self.username; // use username until real address has been loaded
self.updateMails();
} else {
- self.address = null;
- self.mails = [];
+ self.randomize();
}
}
self.inputFieldUsername = self.username;
@@ -82,15 +83,16 @@ app.controller('MailboxController', ["$interval", "$http", "$log", function ($in
};
self.loadEmailsAsync = function (username) {
- $log.debug("updating mails for ", username);
$http.get(backend_url, {params: {username: username}})
.then(function successCallback(response) {
- $log.debug("received mails for ", username);
if (response.data.mails) {
self.error = null;
self.mails = response.data.mails;
self.address = response.data.address;
self.username = response.data.username;
+ if (self.inputFieldUsername === self.username) {
+ self.inputFieldUsername = self.address;
+ }
} else {
self.error = {
title: "JSON_ERROR",
@@ -109,11 +111,13 @@ app.controller('MailboxController', ["$interval", "$http", "$log", function ($in
});
};
- self.deleteMail = function (mailid, index) {
+ self.deleteMail = function (mail, index) {
// instantly remove from frontend.
self.mails.splice(index, 1);
+
// remove on backend.
- $http.get(backend_url, {params: {username: self.username, delete_email_id: mailid}})
+ var firstTo = Object.keys(mail.to)[0];
+ $http.get(backend_url, {params: {username: firstTo, delete_email_id: mail.id}})
.then(
function successCallback(response) {
self.updateMails();
diff --git a/src/client-libs/octicon-inbox.gif b/src/client-libs/octicon-inbox.gif
deleted file mode 100644
index 76a1518..0000000
Binary files a/src/client-libs/octicon-inbox.gif and /dev/null differ
diff --git a/src/client-libs/style.css b/src/client-libs/style.css
index 8776b2c..4f09eff 100644
--- a/src/client-libs/style.css
+++ b/src/client-libs/style.css
@@ -17,15 +17,15 @@ div.min-height {
min-height: 400px;
}
-.nav-container {
+header {
background-color: #D9E2E9;
+ /* leave some space on top */
+ padding-top: 5px;
}
-.octicon-inbox {
- display: inline-block;
- width: 26px;
- height: 23px;
- background: url('octicon-inbox.gif') no-repeat;
+#openRandomButton {
+ /* center vertically */
+ margin-top: 6px;
}
.sticky-header {
@@ -81,3 +81,4 @@ div.min-height {
div.min-height {
min-height: 400px;
}
+
diff --git a/src/config.sample.php b/src/config.sample.php
index 97154c5..9c03143 100644
--- a/src/config.sample.php
+++ b/src/config.sample.php
@@ -12,11 +12,13 @@ error_reporting(E_ALL);
// see https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
// header("Access-Control-Allow-Origin: *");
-// setup imap connection
-$config['imap']['host'] = "localhost";
-$config['imap']['url'] = '{' . $config['imap']['host'] . '/imap/ssl}INBOX';
+// Change IMAP settings (check SSL flags on http://php.net/manual/en/function.imap-open.php)
+$config['imap']['url'] = '{example.com/imap/ssl}INBOX';
$config['imap']['username'] = "test";
$config['imap']['password'] = "test";
// email domain, usually different from imap hostname:
$config['mailHostname'] = "example.com";
+
+// When to delete old messages?
+$config['delete_messages_older_than'] = '30 days ago';
\ No newline at end of file
diff --git a/src/favicon.gif b/src/favicon.gif
new file mode 100644
index 0000000..b4174b3
Binary files /dev/null and b/src/favicon.gif differ
diff --git a/src/index.html b/src/index.html
index 5bba59c..a40a7c2 100644
--- a/src/index.html
+++ b/src/index.html
@@ -8,38 +8,40 @@
-
+
-
-
-
-
+
@@ -53,28 +55,38 @@
browser and your php error logs.
-
- Use the buttons above to create a new inbox, or open a specific mailbox.
-
-
-
Inbox is empty.
+
Your mailbox {{$ctrl.address}} is ready.
+
Emails will appear here automatically. They will be deleted after 30 days.
-
-
Emails to {{address}} will be automatically displayed on this page.
+
+
-
+
-
-
-
-
+