Email Files to Yourself (Drop Folder → Send)
A tiny email files to myself tool you can host on your own site. Upload a file, add an optional note, and it emails you either an attachment (small files) or a download link (bigger files).
Why it’s useful: You’re on a device where logging into cloud storage is annoying, blocked, or you just want a dead-simple “send to me” button. This gives you a private dropbox you control.
What it does:
- Upload a file from any browser.
- Emails you:
- Attachment for small files (configurable limit), or
- Secure download link for larger files.
- No database — stores uploads in a folder.
- Optional basic-auth gate (simple protection).
Install:
- Create:
/tools/send-to-me/ - Create writable folder:
/tools/send-to-me/_up/ - Save the script below as:
/tools/send-to-me/index.php - Edit
$TO_EMAILand the password near the top. - Visit:
/tools/send-to-me/
<?php
declare(strict_types=1);
/**
* Email Files to Yourself — One File (No DB)
* /tools/send-to-me/index.php
*
* Upload a file and email yourself an attachment (small) or a download link (large).
*
* NOTE:
* - This uses PHP mail(). If your host blocks mail(), use SMTP via PHPMailer instead.
* - Keep this private (basic auth + random folder path recommended).
*/
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: strict-origin-when-cross-origin');
// ----------------- CONFIG -----------------
$TO_EMAIL = 'you@example.com'; // <-- change
$FROM_EMAIL = 'noreply@yourdomain.com'; // <-- change to a domain you control
$TO_NAME = 'Me';
$SUBJECT = 'File drop';
// Attachment threshold (bytes). Above this, send a link instead.
$ATTACH_MAX = 2_500_000; // ~2.5MB
// Upload rules
$UPLOAD_DIR = __DIR__ . '/_up';
$MAX_BYTES = 25_000_000; // 25MB
$ALLOWED_EXT = ['jpg','jpeg','png','gif','webp','pdf','txt','zip','mp4','mov','webm','csv','json','doc','docx'];
// Link settings (for large files)
$LINK_TTL_HOURS = 72; // expires in 3 days
$SECRET_SALT = 'CHANGE_THIS_LONG_RANDOM_STRING'; // <-- change
$BASE_URL = ''; // leave blank to auto-detect
// Optional basic auth (recommended)
$AUTH_USER = 'admin';
$AUTH_PASS = 'CHANGE_ME_PASS';
// ----------------- /CONFIG -----------------
function h(string $s): string { return htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); }
function is_https(): bool {
if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') return true;
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && stripos((string)$_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0) return true;
return false;
}
function detect_base_url(): string {
$proto = is_https() ? 'https://' : 'http://';
$host = $_SERVER['HTTP_HOST'] ?? '';
$path = $_SERVER['SCRIPT_NAME'] ?? '';
return $proto . $host . $path;
}
function ensure_dir(string $dir): bool {
return is_dir($dir) || @mkdir($dir, 0755, true);
}
function slug_name(string $s): string {
$s = trim($s);
$s = preg_replace('/[^\w\.\-]+/u', '_', $s) ?? $s;
$s = preg_replace('/_+/', '_', $s) ?? $s;
return trim($s, '_');
}
function sign_token(string $id, int $exp, string $salt): string {
return hash_hmac('sha256', $id . '|' . $exp, $salt);
}
function build_link(string $id, int $exp, string $sig): string {
$base = $GLOBALS['BASE_URL'];
if ($base === '') $base = detect_base_url();
return $base . '?dl=1&id=' . rawurlencode($id) . '&exp=' . $exp . '&sig=' . rawurlencode($sig);
}
function send_mail_plain(string $to, string $subject, string $body, string $fromEmail, string $fromName): bool {
$headers = [];
$headers[] = 'From: ' . $fromName . ' <' . $fromEmail . '>';
$headers[] = 'MIME-Version: 1.0';
$headers[] = 'Content-Type: text/plain; charset=UTF-8';
return @mail($to, $subject, $body, implode("\r\n", $headers));
}
function send_mail_with_attachment(string $to, string $subject, string $body, string $fromEmail, string $fromName, string $filePath, string $fileName): bool {
$boundary = 'b_' . bin2hex(random_bytes(12));
$headers = [];
$headers[] = 'From: ' . $fromName . ' <' . $fromEmail . '>';
$headers[] = 'MIME-Version: 1.0';
$headers[] = 'Content-Type: multipart/mixed; boundary="'.$boundary.'"';
$msg = "--{$boundary}\r\n";
$msg .= "Content-Type: text/plain; charset=UTF-8\r\n\r\n";
$msg .= $body . "\r\n\r\n";
$bin = @file_get_contents($filePath);
if ($bin === false) return false;
$b64 = chunk_split(base64_encode($bin));
$msg .= "--{$boundary}\r\n";
$msg .= "Content-Type: application/octet-stream; name=\"".addslashes($fileName)."\"\r\n";
$msg .= "Content-Transfer-Encoding: base64\r\n";
$msg .= "Content-Disposition: attachment; filename=\"".addslashes($fileName)."\"\r\n\r\n";
$msg .= $b64 . "\r\n";
$msg .= "--{$boundary}--\r\n";
return @mail($to, $subject, $msg, implode("\r\n", $headers));
}
// -------- Basic auth gate --------
if ($AUTH_USER !== '' && $AUTH_PASS !== '') {
$u = $_SERVER['PHP_AUTH_USER'] ?? '';
$p = $_SERVER['PHP_AUTH_PW'] ?? '';
if ($u !== $AUTH_USER || $p !== $AUTH_PASS) {
header('WWW-Authenticate: Basic realm="Send To Me"');
http_response_code(401);
echo "Auth required.";
exit;
}
}
ensure_dir($UPLOAD_DIR);
// -------- Download handler (for link emails) --------
if (isset($_GET['dl'], $_GET['id'], $_GET['exp'], $_GET['sig'])) {
$id = (string)$_GET['id'];
$exp = (int)$_GET['exp'];
$sig = (string)$_GET['sig'];
if ($exp < time()) { http_response_code(410); echo "Link expired."; exit; }
$good = sign_token($id, $exp, $SECRET_SALT);
if (!hash_equals($good, $sig)) { http_response_code(403); echo "Bad signature."; exit; }
$metaFile = $UPLOAD_DIR . '/' . $id . '.json';
$meta = is_file($metaFile) ? json_decode((string)file_get_contents($metaFile), true) : null;
if (!is_array($meta)) { http_response_code(404); echo "Not found."; exit; }
$path = $UPLOAD_DIR . '/' . ($meta['stored'] ?? '');
if (!is_file($path)) { http_response_code(404); echo "Missing file."; exit; }
$orig = (string)($meta['name'] ?? 'download.bin');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.str_replace('"','', $orig).'"');
header('Content-Length: ' . (string)filesize($path));
readfile($path);
exit;
}
// -------- Upload handler --------
$okMsg = '';
$errMsg = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$note = trim((string)($_POST['note'] ?? ''));
$f = $_FILES['file'] ?? null;
if (!is_array($f) || (int)($f['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
$errMsg = 'Upload failed.';
} else {
$size = (int)($f['size'] ?? 0);
if ($size <= 0 || $size > $MAX_BYTES) $errMsg = 'File too large (max ' . (int)round($MAX_BYTES/1024/1024) . 'MB).';
$orig = (string)($f['name'] ?? 'file');
$ext = strtolower(pathinfo($orig, PATHINFO_EXTENSION));
if ($errMsg === '' && $ext !== '' && !in_array($ext, $ALLOWED_EXT, true)) $errMsg = 'File type not allowed.';
if ($errMsg === '') {
$id = gmdate('Ymd_His') . '_' . bin2hex(random_bytes(6));
$safeOrig = slug_name($orig);
if ($safeOrig === '') $safeOrig = 'file.' . ($ext ?: 'bin');
$stored = $id . '_' . $safeOrig;
$dest = $UPLOAD_DIR . '/' . $stored;
if (!@move_uploaded_file((string)$f['tmp_name'], $dest)) {
$errMsg = 'Could not save file (permissions?).';
} else {
// Save meta for link downloads
$meta = [
'id' => $id,
'name' => $orig,
'stored' => $stored,
'size' => $size,
'note' => $note,
'createdAt' => gmdate('c'),
];
@file_put_contents($UPLOAD_DIR . '/' . $id . '.json', json_encode($meta, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOCK_EX);
$body = "New file drop\n\n";
$body .= "File: {$orig}\n";
$body .= "Size: " . round($size/1024, 1) . " KB\n";
if ($note !== '') $body .= "\nNote:\n{$note}\n";
$sent = false;
if ($size <= $ATTACH_MAX) {
$sent = send_mail_with_attachment($TO_EMAIL, $SUBJECT, $body, $FROM_EMAIL, $TO_NAME, $dest, $orig);
if (!$sent) {
// fallback to link
$exp = time() + ($LINK_TTL_HOURS * 3600);
$sig = sign_token($id, $exp, $SECRET_SALT);
$link = build_link($id, $exp, $sig);
$body .= "\n\n(Attachment failed; sending link instead)\n";
$body .= "Download link (expires in {$LINK_TTL_HOURS}h):\n{$link}\n";
$sent = send_mail_plain($TO_EMAIL, $SUBJECT, $body, $FROM_EMAIL, $TO_NAME);
}
} else {
$exp = time() + ($LINK_TTL_HOURS * 3600);
$sig = sign_token($id, $exp, $SECRET_SALT);
$link = build_link($id, $exp, $sig);
$body .= "\n\nDownload link (expires in {$LINK_TTL_HOURS}h):\n{$link}\n";
$sent = send_mail_plain($TO_EMAIL, $SUBJECT, $body, $FROM_EMAIL, $TO_NAME);
}
if ($sent) $okMsg = 'Sent! Check your inbox.';
else $errMsg = 'Mail failed. Your host may block PHP mail().';
}
}
}
}
?><!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Email Files to Yourself</title>
<meta name="description" content="Upload a file and email it to yourself as an attachment (small) or a secure download link (large). Lightweight, no database." />
<meta name="robots" content="index,follow" />
<style>
:root{
--bg:#0b0f16; --panel:#111a26; --panel2:#0c1420;
--text:#e8eef8; --muted:rgba(232,238,248,.72);
--line:rgba(255,255,255,.10); --accent:#2a8cff;
--shadow:0 18px 55px rgba(0,0,0,.45); --r:16px;
--ok:#7CFF9A; --bad:#FF7C7C;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--text);font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif}
.wrap{max-width:760px;margin:0 auto;padding:18px}
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:14px;margin:12px 0;box-shadow:var(--shadow)}
.pill{display:inline-block;padding:4px 10px;border-radius:999px;background:rgba(42,140,255,.14);border:1px solid rgba(42,140,255,.25);font-weight:900;font-size:12px}
.muted{color:var(--muted)}
input,textarea{
width:100%;padding:10px 12px;border-radius:12px;border:1px solid var(--line);
background:var(--panel2);color:var(--text);outline:none;
font:700 13px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;
}
textarea{min-height:120px;resize:vertical;font-weight:650;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;line-height:1.45;border-radius:14px}
.btn{
display:inline-flex;align-items:center;justify-content:center;gap:8px;
border:0;border-radius:12px;padding:10px 12px;background:var(--accent);
color:#06101a;font-weight:950;cursor:pointer;
}
.ok{color:var(--ok);font-weight:950}
.bad{color:var(--bad);font-weight:950}
.hr{height:1px;background:var(--line);margin:12px 0}
.small{font-size:12px}
</style>
</head>
<body>
<div class="wrap">
<div class="card">
<div class="pill">Utility</div>
<h1 style="margin:10px 0 6px;font-size:22px">Email Files to Yourself</h1>
<div class="muted">Upload a file → get it emailed as an attachment (small) or a secure link (large).</div>
<?php if ($okMsg): ?><div class="hr"></div><div class="ok"><?php echo h($okMsg); ?></div><?php endif; ?>
<?php if ($errMsg): ?><div class="hr"></div><div class="bad"><?php echo h($errMsg); ?></div><?php endif; ?>
</div>
<div class="card">
<form method="post" enctype="multipart/form-data" style="display:grid;gap:10px">
<div>
<div class="muted small" style="margin-bottom:6px">Choose a file</div>
<input type="file" name="file" required />
<div class="muted small" style="margin-top:6px">
Max upload: <b><?php echo (int)round($MAX_BYTES/1024/1024); ?>MB</b> •
Attach up to: <b><?php echo (int)round($ATTACH_MAX/1024/1024); ?>MB</b>
</div>
</div>
<div>
<div class="muted small" style="margin-bottom:6px">Optional note</div>
<textarea name="note" placeholder="Anything you want to remember about this file..."></textarea>
</div>
<button class="btn" type="submit">📨 Send to me</button>
</form>
</div>
<div class="card">
<b>Security tips</b>
<div class="muted small" style="margin-top:8px;line-height:1.55">
<ul style="margin:0;padding-left:18px">
<li>Keep it behind Basic Auth (already included).</li>
<li>Change <span class="muted">ADMIN</span> credentials + <code>$SECRET_SALT</code>.</li>
<li>Consider placing this tool in a non-obvious path (<code>/tools/_drop_9f3a/</code>).</li>
<li>Limit allowed file types if you only need a few.</li>
</ul>
</div>
</div>
</div>
</body>
</html>
Comments (0)
No comments yet — be the first.