Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/java/uk/co/bigsoft/greenmail/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import uk.co.bigsoft.greenmail.http.commands.DeleteMessageCommand;
import uk.co.bigsoft.greenmail.http.commands.AddUserCommand;
import uk.co.bigsoft.greenmail.http.commands.DeleteUserCommand;
import uk.co.bigsoft.greenmail.http.commands.EmlExportCommand;
import uk.co.bigsoft.greenmail.http.commands.EmlImportCommand;
import uk.co.bigsoft.greenmail.http.commands.ImapAllMessagesCommand;
import uk.co.bigsoft.greenmail.http.commands.ImapGetInBoxCommand;
import uk.co.bigsoft.greenmail.http.commands.ImapListMailBoxCommand;
Expand Down Expand Up @@ -79,6 +81,8 @@ private static void startHttpServer(GreenMail greenMail) {
app.get("/dn/:domain/to", new ListDomainMessageCommand(greenMail, "to"));
app.get("/dn/:domain/cc", new ListDomainMessageCommand(greenMail, "cc"));
app.get("/dn/:domain/bcc", new ListDomainMessageCommand(greenMail, "bcc"));
app.post("/import", new EmlImportCommand(greenMail));
app.get("/export/:mailbox/:uid", new EmlExportCommand(greenMail));

if (cfg.useAccessControlAnywhere()) {
System.out.println("Allow REST connections from anywhere");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package uk.co.bigsoft.greenmail.http.commands;

import java.io.ByteArrayOutputStream;

import javax.mail.internet.MimeMessage;

import com.icegreen.greenmail.store.MailFolder;
import com.icegreen.greenmail.store.StoredMessage;
import com.icegreen.greenmail.util.GreenMail;

import io.javalin.http.Context;

public class EmlExportCommand extends BaseHandler {

public EmlExportCommand(GreenMail greenMail) {
super(greenMail);
}

@Override
public void handle(Context ctx) throws Exception {
MailFolder mailbox = utils.getMailbox(ctx, im);
long uid = utils.getUid(ctx);
StoredMessage sm = mailbox.getMessage(uid);
MimeMessage mime = sm.getMimeMessage();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mime.writeTo(baos);
byte[] bytes = baos.toByteArray();
ctx.result(bytes);
ctx.header("Content-Disposition", "attachment; filename=\"email.eml\"");
ctx.header("Content-Type", "text/plain; charset=utf-8");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package uk.co.bigsoft.greenmail.http.commands;

import javax.mail.Session;
import javax.mail.internet.MimeMessage;

import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.GreenMailUtil;
import com.icegreen.greenmail.util.ServerSetup;

import io.javalin.http.Context;
import io.javalin.http.UploadedFile;

public class EmlImportCommand extends BaseHandler {

public EmlImportCommand(GreenMail greenMail) {
super(greenMail);
}

@Override
public void handle(Context ctx) throws Exception {
ServerSetup setup = new ServerSetup(gm.getSmtp().getPort(), gm.getSmtp().getBindTo(), ServerSetup.PROTOCOL_SMTP);
setup.setServerStartupTimeout(ServerSetup.SERVER_STARTUP_TIMEOUT);
Session session = GreenMailUtil.getSession(setup);
for (UploadedFile file : ctx.uploadedFiles()) {
MimeMessage mime = new MimeMessage(session, file.getContent());
GreenMailUtil.sendMimeMessage(mime);
}
ctx.json("OK");
}
}
13 changes: 12 additions & 1 deletion src/main/web/src/c/GmhUrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ let mappings = {
DELETE_MAILBOX: '/m/:mailbox/delete',
DELETE_USER: '/u/:email/delete',
ADD_USER: '/u/add',
SEND_EMAIL: '/send'
SEND_EMAIL: '/send',
EML_IMPORT: '/import',
EML_EXPORT: '/export/:mailbox/:uid'
}

export let ServerConfig = () => {
Expand Down Expand Up @@ -83,3 +85,12 @@ export let AddUserUrl = () => {
export let SendEmailUrl = () => {
return base + mappings.SEND_EMAIL
}

export let EmlImportUrl = () => {
return base + mappings.EML_IMPORT
}

export let EmlExportUrl = (mailbox, uid) => {
let encMailbox = encodeURIComponent(mailbox)
return base + mappings.EML_EXPORT.replace(':mailbox', encMailbox).replace(':uid', uid)
}
104 changes: 104 additions & 0 deletions src/main/web/src/c/ImportEmail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, {Component} from 'react'
import DialogTitle from '@material-ui/core/DialogTitle'
import Button from '@material-ui/core/Button'
import Dialog from '@material-ui/core/Dialog'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent/DialogContent'
import axios from 'axios'
import {EmlImportUrl} from '../c/GmhUrl'
import SendIcon from '@material-ui/icons/Send'
import {ValidatorForm} from 'react-material-ui-form-validator'
import Typography from '@material-ui/core/Typography'
import CloseIcon from '@material-ui/icons/Close'
import PublishIcon from '@material-ui/icons/Publish'
import {Tooltip} from '@material-ui/core'

class ImportEmail extends Component{

constructor(props){
super(props)
this.state = {
openEmailDialog: false,
errorMessage: '',
file: null
}
}

openDialog = () => {
this.setState({
openEmailDialog: true
})
}

sendEmail = () => {
let url = EmlImportUrl()
let formData = new FormData();
formData.append("email", this.state.file);
axios.post(url,formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then( res => {
this.closeDialog()
this.props.reload()
}, (error) => {
this.setState({
errorMessage: error.toString()
})
})
}

closeDialog = () => {
this.setState({
openEmailDialog: false
})
}

handleChange = (event) => {
if (event.target.files) {
this.setState({
file : event.target.files[0]
})
}
}

render(){
return (
<span>
<Tooltip title="Import Email from .eml file">
<Button onClick={this.openDialog} class="btn btn-primary" style={{margin:2}}>
<PublishIcon/>Import
</Button>
</Tooltip>

<Dialog fullWidth onClose={this.closeDialog} aria-labelledby="customized-dialog-title" open={this.state.openEmailDialog}>
<DialogTitle id="compose-email-title" onClose={this.closeDialog}>
Import Email from .eml file
<Button style={{float: 'right'}} onClick={this.closeDialog}>
<CloseIcon/>
</Button>
</DialogTitle>
<DialogContent dividers>

<Typography style={{color: 'red', marginLeft: 30}}>{this.state.errorMessage}</Typography>

<ValidatorForm onSubmit={this.sendEmail}>
<DialogContent>
<input type="file" onChange={this.handleChange} style={{width: "100%"}}/>
</DialogContent>

<DialogActions>
<Button type="submit" color="primary">
<SendIcon/>
Import
</Button>
</DialogActions>
</ValidatorForm>
</DialogContent>
</Dialog>
</span>
)
}
}

export default ImportEmail
3 changes: 3 additions & 0 deletions src/main/web/src/c/MessagesTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import RefreshIcon from '@material-ui/icons/Refresh'
import {Tooltip} from '@material-ui/core'
import Card from '@material-ui/core/Card'
import ComposeEmailDialog from './ComposeEmailDialog'
import ImportEmail from './ImportEmail'

function MessagesTable(props) {

Expand All @@ -21,6 +22,8 @@ function MessagesTable(props) {
<div>
<div>
<ComposeEmailDialog reload={reload}/>

<ImportEmail reload={reload}/>

<Tooltip title="Refresh">
<Button onClick={reload}>
Expand Down
12 changes: 11 additions & 1 deletion src/main/web/src/p/ViewMessagePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {Component} from 'react'
import axios from 'axios'
import Alert from 'react-bootstrap/Alert'
import Table from '@material-ui/core/Table'
import {ViewMessageUrl} from '../c/GmhUrl'
import {EmlExportUrl, ViewMessageUrl} from '../c/GmhUrl'
import EmailAddresses from '../c/EmailAddresses'
import {BreadcrumbContext} from '../c/breadcrumbContext'
import PageHeader from '../m/PageHeader'
Expand All @@ -12,6 +12,8 @@ import Paper from '@material-ui/core/Paper'
import Tabs from '@material-ui/core/Tabs'
import Tab from '@material-ui/core/Tab'
import TableCell from '@material-ui/core/TableCell/TableCell'
import GetAppIcon from '@material-ui/icons/GetApp'
import Button from '@material-ui/core/Button'

class ViewMessagePage extends Component {

Expand Down Expand Up @@ -133,10 +135,18 @@ class ViewMessagePage extends Component {
const eMessage = this.state.data.toString() + " " +this.state.url
return <Alert variant="danger" dismissible>{eMessage}</Alert>
}
const {mailbox, uid} = this.props.match.params
const url = EmlExportUrl(mailbox, uid)

return (
<div>
<PageHeader title="Message"/>
<a href={url} target="_blank" rel="noopener noreferrer" download>
<Button class="btn btn-primary">
<GetAppIcon/>
Export Email
</Button>
</a>
<Paper>
<Tabs
value={this.state.value}
Expand Down