Merge branch 'develop'

This commit is contained in:
Alexandre Bodin 2020-05-18 09:55:53 +02:00
commit 1ab5afc33d
61 changed files with 387 additions and 1276 deletions

View File

@ -168,20 +168,18 @@ module.exports = ({ env }) => ({
**Available options**
| Property | Description | Type | Default |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ----------- |
| `host` | Host name | string | `localhost` |
| `port` | Port on which the server should be running. | integer | `1337` |
| `emitErrors` | Enable errors to be emitted to `koa` when they happen in order to attach custom logic or use error reporting services. | boolean | |
| `url` | Url of the server. Enable proxy support such as Apache or Nginx, example: `https://mywebsite.com/api`. Default value: `http://${host}:${port}`. | string | |
| `cron` | Cron configuration (powered by [`node-schedule`](https://github.com/node-schedule/node-schedule)) | Object | |
| `cron.enabled` | Enable or disable CRON tasks to schedule jobs at specific dates. | boolean | `false` |
| `admin` | Admin panel configuration | Object | |
| `admin.url` | Url of your admin panel. Default value: `/admin`. Note: If the url is relative, it will be concatenated with `url`. | string | `/admin` |
| `admin.autoOpen` | Enable or disabled administration opening on start. | boolean | `true` |
| `admin.watchIgnoreFiles` | Add custom files that should not be watched during development. See more [here](https://github.com/paulmillr/chokidar#path-filtering) (property `ignored`). | Array(string) | `[]`. |
| `admin.build` | Admin panel build configuration | Object | |
| `admin.build.backend` | URL that the admin panel and plugins will request | string | |
| Property | Description | Type | Default |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- | ----------- |
| `host` | Host name | string | `localhost` |
| `port` | Port on which the server should be running. | integer | `1337` |
| `emitErrors` | Enable errors to be emitted to `koa` when they happen in order to attach custom logic or use error reporting services. | boolean | `false |
| `url` | Url of the server. Enable proxy support such as Apache or Nginx, example: `https://mywebsite.com/api`. The url can be relative, if so, it is used with `http://${host}:${port}` as the base url. | string | `''` |
| `cron` | Cron configuration (powered by [`node-schedule`](https://github.com/node-schedule/node-schedule)) | Object | |
| `cron.enabled` | Enable or disable CRON tasks to schedule jobs at specific dates. | boolean | `false` |
| `admin` | Admin panel configuration | Object | |
| `admin.url` | Url of your admin panel. Default value: `/admin`. Note: If the url is relative, it will be concatenated with `url`. | string | `/admin` |
| `admin.autoOpen` | Enable or disabled administration opening on start. | boolean | `true` |
| `admin.watchIgnoreFiles` | Add custom files that should not be watched during development. See more [here](https://github.com/paulmillr/chokidar#path-filtering) (property `ignored`). | Array(string) | `[]`. |
## Functions

View File

@ -12,7 +12,7 @@ Update your package.json accordingly:
```json
{
//...
// ...
"dependencies": {
"strapi": "3.0.0-beta.20",
"strapi-admin": "3.0.0-beta.20",

View File

@ -11,7 +11,9 @@ By using the following function, strapi will use the configured provider to send
await strapi.plugins['email'].services.email.send({
to: 'paulbocuse@strapi.io',
from: 'joelrobuchon@strapi.io',
replyTo: 'no-reply@strapi.io',
cc: 'helenedarroze@strapi.io',
bcc: 'ghislainearabian@strapi.io',
replyTo: 'annesophiepic@strapi.io',
subject: 'Use strapi email provider successfully',
text: 'Hello world!',
html: 'Hello world!',
@ -20,15 +22,9 @@ await strapi.plugins['email'].services.email.send({
## Configure the plugin
The plugin provides you a settings page where you can define the email provider you want to use.
You will also be able to add some configuration.
### Install the provider you want
- Click on **Plugins** in the left menu
- Click on the cog button on the **Email** plugin line
## Install new providers
By default Strapi provides a local email system. You might want to send email with a third party.
By default Strapi provides a local email system ([sendmail](https://www.npmjs.com/package/sendmail)). If you want to use a third party to send emails, you need to install the correct provider module. Otherwise you can skip this part and continue to [Configure your provider](#configure-your-provider).
You can check all the available providers developed by the community on npmjs.org - [Providers list](https://www.npmjs.com/search?q=strapi-provider-email-)
@ -54,29 +50,44 @@ npm install strapi-provider-email-sendgrid@beta --save
::::
::: tip
If the provider is not in the mono repo, you probably don't need `@beta` depending if the creator published it with this tag or not.
:::
### Configure your provider
Then, visit [http://localhost:1337/admin/plugins/email/configurations/development](http://localhost:1337/admin/plugins/email/configurations/development) on your web browser and configure the provider.
After installing your provider you will need to add some settings in `config/plugins.js`. Check the README of each provider to know what configuration settings the provider needs.
Here is an example of a configuration made for the provider [strapi-provider-email-sendgrid](https://www.npmjs.com/package/strapi-provider-email-sendgrid).
**Path —** `./config/plugins.js`.
```js
module.exports = ({ env }) => ({
// ...
email: {
provider: 'sendgrid',
providerOptions: {
apiKey: env('SENDGRID_API_KEY'),
},
settings: {
defaultFrom: 'juliasedefdjian@strapi.io',
defaultReplyTo: 'juliasedefdjian@strapi.io',
},
},
// ...
});
```
::: tip
If you're using a different provider depending on your environment, you can specify the correct configuration in `config/env/${yourEnvironment}/plugins.js`. More info here: [Environments](../concepts/configurations#environments)
:::
## Create new provider
If you want to create your own, make sure the name starts with `strapi-provider-email-` (duplicating an existing one will be easier), modify the `auth` config object and customize the `send` function.
If you want to create your own, make sure the name starts with `strapi-provider-email-` (duplicating an existing one will be easier) and customize the `send` function.
Default template
```js
module.exports = {
provider: 'provider-id',
name: 'display name',
auth: {
config_1: {
label: 'My Config 1',
type: 'text',
},
},
init: config => {
init: (providerOptions = {}, settings = {}) => {
return {
send: async options => {},
};
@ -86,7 +97,8 @@ module.exports = {
In the `send` function you will have access to:
- `config` that contains configurations you setup in your admin panel
- `providerOptions` that contains configurations written in `plugins.js`
- `settings` that contains configurations written in `plugins.js`
- `options` that contains options you send when you call the `send` function from the email plugin service
To use it you will have to publish it on **npm**.
@ -147,6 +159,6 @@ Error: SMTP code:550 msg:550-5.7.1 [87.88.179.13] The IP you're using to send ma
550 5.7.1 https://support.google.com/mail/?p=NotAuthorizedError 30si2132728pjz.75 - gsmtp
```
To fix it, I suggest you to use another email provider that uses third party to send emails.
To fix it, we suggest you to use another email provider that uses third party to send emails.
When using a third party provider, you avoid having to setup a mail server on your server and get extra features such as email analytics.

View File

@ -82,6 +82,7 @@ ssl
nbproject
public/uploads/*
!public/uploads/.gitkeep
.env
############################
# Node.js

View File

@ -1,6 +1,6 @@
module.exports = {
module.exports = ({ env }) => ({
graphql: {
amountLimit: 5,
depthLimit: 10,
},
};
});

View File

@ -11,8 +11,6 @@ import { Button, PopUpWarning } from 'strapi-helper-plugin';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Wrapper from './Wrapper';
const PLUGINS_WITH_CONFIG = ['email'];
/* eslint-disable react/no-unused-state */
class PluginCard extends React.Component {
state = {
@ -92,13 +90,7 @@ class PluginCard extends React.Component {
? 'app.components.PluginCard.Button.label.install'
: 'app.components.PluginCard.Button.label.download';
// Display settings link for a selection of plugins.
const settingsComponent = PLUGINS_WITH_CONFIG.includes(this.props.plugin.id) && (
<div className="settings" onClick={this.handleClickSettings}>
<FontAwesomeIcon icon="cog" />
<FormattedMessage id="app.components.PluginCard.settings" />
</div>
);
const settingsComponent = null;
const descriptions = {
short:

View File

@ -3,31 +3,17 @@ import PropTypes from 'prop-types';
import { IconLinks } from '@buffetjs/core';
import { useGlobalContext, PopUpWarning } from 'strapi-helper-plugin';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useHistory } from 'react-router-dom';
import { faTrashAlt, faCog } from '@fortawesome/free-solid-svg-icons';
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons';
import Text from '../../components/Text';
import CustomRow from './CustomRow';
import LogoContainer from './Logo';
const PLUGINS_WITH_CONFIG = ['email'];
const Row = ({ logo, name, description, isRequired, id, icon, onConfirm }) => {
const { currentEnvironment, formatMessage } = useGlobalContext();
const { formatMessage } = useGlobalContext();
const [isOpen, setIsOpen] = useState(false);
const { push } = useHistory();
const links = [];
if (PLUGINS_WITH_CONFIG.includes(id)) {
links.push({
icon: <FontAwesomeIcon icon={faCog} />,
onClick: () => {
const settingsPath = `/plugins/${id}/configurations/${currentEnvironment}`;
push(settingsPath);
},
});
}
const handleClickConfirm = () => {
handleToggle();
onConfirm(id);

View File

@ -316,11 +316,6 @@ module.exports = {
const resetPasswordToken = crypto.randomBytes(64).toString('hex');
const settings = {
from: {
name: 'Administration Panel',
email: 'no-reply@strapi.io',
},
response_email: '',
object: 'Reset password',
message: `<p>We heard that you lost your password. Sorry about that!</p>
@ -335,12 +330,7 @@ module.exports = {
// Send an email to the admin.
await strapi.plugins['email'].services.email.send({
to: admin.email,
from:
settings.from.email || settings.from.name
? `${settings.from.name} <${settings.from.email}>`
: undefined,
replyTo: settings.response_email,
subject: settings.object,
subject: 'Reset password',
text: settings.message,
html: settings.message,
});

View File

@ -1,24 +0,0 @@
import styled from 'styled-components';
const Wrapper = styled.div`
background: #ffffff;
padding: 45px 30px 22px 30px;
border-radius: 2px;
box-shadow: 0 2px 4px #e3e9f3;
.inputStyle {
max-width: 358px;
}
.input-wrapper {
margin-bottom: 1.1rem;
}
.subFormWrapper {
margin-bottom: 14px;
padding: 23px 30px 0 30px;
background-color: #fafafb;
}
`;
export default Wrapper;

View File

@ -1,97 +0,0 @@
/**
*
* EditForm
*
*/
import React from 'react';
import { findIndex, get, isEmpty, map } from 'lodash';
import PropTypes from 'prop-types';
import { InputsIndex as Input } from 'strapi-helper-plugin';
import Wrapper from './Wrapper';
class EditForm extends React.Component {
getProviderForm = () =>
get(
this.props.settings,
['providers', this.props.selectedProviderIndex, 'auth'],
{}
);
generateSelectOptions = () =>
Object.keys(get(this.props.settings, 'providers', {})).reduce(
(acc, current) => {
const option = {
id: get(this.props.settings, ['providers', current, 'name']),
value: get(this.props.settings, ['providers', current, 'provider']),
};
acc.push(option);
return acc;
},
[]
);
render() {
return (
<Wrapper>
<div className="row">
<Input
customBootstrapClass="col-md-6"
inputDescription={{
id: 'email.EditForm.Input.select.inputDescription',
}}
className="input-wrapper"
inputClassName="inputStyle"
label={{ id: 'email.EditForm.Input.select.label' }}
name="provider"
onChange={this.props.onChange}
selectOptions={this.generateSelectOptions()}
type="select"
value={get(this.props.modifiedData, 'provider')}
/>
</div>
{!isEmpty(this.getProviderForm()) && (
<div className="subFormWrapper">
<div className="row">
{map(this.getProviderForm(), (value, key) => (
<Input
didCheckErrors={this.props.didCheckErrors}
errors={get(this.props.formErrors, [
findIndex(this.props.formErrors, ['name', key]),
'errors',
])}
key={key}
label={{ id: value.label }}
name={key}
onChange={this.props.onChange}
selectOptions={value.values}
type={value.type === 'enum' ? 'select' : value.type}
validations={{ required: true }}
value={get(this.props.modifiedData, key, '')}
/>
))}
</div>
</div>
)}
</Wrapper>
);
}
}
EditForm.defaultProps = {
settings: {
providers: [],
},
};
EditForm.propTypes = {
didCheckErrors: PropTypes.bool.isRequired,
formErrors: PropTypes.array.isRequired,
modifiedData: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
selectedProviderIndex: PropTypes.number.isRequired,
settings: PropTypes.object,
};
export default EditForm;

View File

@ -1,36 +0,0 @@
/**
*
* This component is the skeleton around the actual pages, and should only
* contain code that should be seen on all pages. (e.g. navigation bar)
*
*/
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import pluginId from '../../pluginId';
// Containers
import ConfigPage from '../ConfigPage';
function App() {
return (
<div className={pluginId}>
<Switch>
<Route
path={`/plugins/${pluginId}/configurations/:env`}
component={ConfigPage}
exact
/>
<Route
path={`/plugins/${pluginId}/configurations/`}
component={ConfigPage}
exact
/>
<Route path={`/plugins/${pluginId}`} component={ConfigPage} exact />
</Switch>
</div>
);
}
export default App;

View File

@ -1,77 +0,0 @@
/**
*
*
* ConfigPage actions
*
*/
import {
GET_SETTINGS,
GET_SETTINGS_SUCCEEDED,
ON_CANCEL,
ON_CHANGE,
SET_ERRORS,
SUBMIT,
SUBMIT_ERROR,
SUBMIT_SUCCEEDED,
} from './constants';
export function getSettings(env) {
return {
type: GET_SETTINGS,
env,
};
}
export function getSettingsSucceeded(settings, appEnvironments) {
return {
type: GET_SETTINGS_SUCCEEDED,
appEnvironments,
settings,
initialData: settings.config,
};
}
export function onCancel() {
return {
type: ON_CANCEL,
};
}
export function onChange({ target }) {
const keys = ['modifiedData'].concat(target.name.split('.'));
const value = target.value;
return {
type: ON_CHANGE,
keys,
value,
};
}
export function setErrors(errors) {
return {
type: SET_ERRORS,
errors,
};
}
export function submit() {
return {
type: SUBMIT,
};
}
export function submitError(errors) {
return {
type: SUBMIT_ERROR,
errors,
};
}
export function submitSucceeded(data) {
return {
type: SUBMIT_SUCCEEDED,
data,
};
}

View File

@ -1,16 +0,0 @@
/**
*
* ConfigPage constants
*
*/
export const GET_ENV = 'Email/ConfigPage/GET_ENV';
export const GET_ENV_SUCCEEDED = 'Email/ConfigPage/GET_ENV_SUCCEEDED';
export const GET_SETTINGS = 'Email/ConfigPage/GET_SETTINGS';
export const GET_SETTINGS_SUCCEEDED = 'Email/ConfigPage/GET_SETTINGS_SUCCEEDED';
export const ON_CANCEL = 'Email/ConfigPage/ON_CANCEL';
export const ON_CHANGE = 'Email/ConfigPage/ON_CHANGE';
export const SET_ERRORS = 'Email/ConfigPage/SET_ERRORS';
export const SUBMIT = 'Email/ConfigPage/SUBMIT';
export const SUBMIT_ERROR = 'Email/ConfigPage/SUBMIT_ERROR';
export const SUBMIT_SUCCEEDED = 'Email/ConfigPage/SUBMIT_SUCCEEDED';

View File

@ -1,190 +0,0 @@
/**
*
* ConfigPage
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
import { findIndex, get, isEmpty } from 'lodash';
import { Header } from '@buffetjs/custom';
// You can find these components in either
// ./node_modules/strapi-helper-plugin/lib/src
// or strapi/packages/strapi-helper-plugin/lib/src
import { ContainerFluid, HeaderNav, GlobalContext } from 'strapi-helper-plugin';
import pluginId from '../../pluginId';
// Plugin's components
import EditForm from '../../components/EditForm';
import { getSettings, onCancel, onChange, setErrors, submit } from './actions';
import saga from './saga';
import selectConfigPage from './selectors';
class ConfigPage extends React.Component {
pluginHeaderActions = [
{
color: 'cancel',
label: this.context.formatMessage({ id: 'app.components.Button.cancel' }),
onClick: this.props.onCancel,
type: 'button',
key: 'button-cancel',
},
{
color: 'success',
label: this.context.formatMessage({ id: 'app.components.Button.save' }),
onClick: this.handleSubmit,
type: 'submit',
key: 'button-submit',
},
];
componentDidMount() {
this.getSettings(this.props);
}
componentDidUpdate(prevProps) {
// Get new settings on navigation change
if (prevProps.match.params.env !== this.props.match.params.env) {
this.getSettings(this.props);
}
// Redirect the user to the email list after modifying is provider
if (prevProps.submitSuccess !== this.props.submitSuccess) {
this.props.history.push(`/plugins/email/configurations/${this.props.match.params.env}`);
}
}
getSelectedProviderIndex = () =>
findIndex(this.props.settings.providers, [
'provider',
get(this.props.modifiedData, 'provider'),
]);
/**
* Get Settings depending on the props
* @param {Object} props
* @return {Func} calls the saga that gets the current settings
*/
getSettings = props => {
const {
match: {
params: { env },
},
} = props;
this.props.getSettings(env);
};
generateLinks = () => {
const headerNavLinks = this.props.appEnvironments
.reduce((acc, current) => {
const link = Object.assign(current, {
to: `/plugins/email/configurations/${current.name}`,
});
acc.push(link);
return acc;
}, [])
.sort(link => link.name === 'production');
return headerNavLinks;
};
handleSubmit = e => {
e.preventDefault();
const formErrors = Object.keys(
get(this.props.settings, ['providers', this.getSelectedProviderIndex(), 'auth'], {})
).reduce((acc, current) => {
if (isEmpty(get(this.props.modifiedData, current, ''))) {
acc.push({
name: current,
errors: [{ id: 'components.Input.error.validation.required' }],
});
}
return acc;
}, []);
if (!isEmpty(formErrors)) {
return this.props.setErrors(formErrors);
}
return this.props.submit();
};
static contextType = GlobalContext;
render() {
const { formatMessage } = this.context;
return (
<div>
<form onSubmit={this.handleSubmit}>
<ContainerFluid>
<Header
actions={this.pluginHeaderActions}
content={formatMessage({
id: 'email.ConfigPage.description',
})}
title={{ label: formatMessage({ id: 'email.ConfigPage.title' }) }}
/>
<HeaderNav links={this.generateLinks()} style={{ marginTop: '4.6rem' }} />
<EditForm
didCheckErrors={this.props.didCheckErrors}
formErrors={this.props.formErrors}
modifiedData={this.props.modifiedData}
onChange={this.props.onChange}
selectedProviderIndex={this.getSelectedProviderIndex()}
settings={this.props.settings}
/>
</ContainerFluid>
</form>
</div>
);
}
}
ConfigPage.defaultProps = {
appEnvironments: [],
formErrors: [],
settings: {
providers: [],
},
};
ConfigPage.propTypes = {
appEnvironments: PropTypes.array,
didCheckErrors: PropTypes.bool.isRequired,
formErrors: PropTypes.array,
getSettings: PropTypes.func.isRequired,
history: PropTypes.object.isRequired,
match: PropTypes.object.isRequired,
modifiedData: PropTypes.object.isRequired,
onCancel: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
setErrors: PropTypes.func.isRequired,
settings: PropTypes.object,
submit: PropTypes.func.isRequired,
submitSuccess: PropTypes.bool.isRequired,
};
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
getSettings,
onCancel,
onChange,
setErrors,
submit,
},
dispatch
);
}
const mapStateToProps = selectConfigPage();
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withSaga = strapi.injectSaga({ key: 'configPage', saga, pluginId });
export default compose(withSaga, withConnect)(ConfigPage);

View File

@ -1,67 +0,0 @@
/**
*
* ConfigPage reducer
*
*/
import { fromJS, List, Map } from 'immutable';
import {
GET_SETTINGS,
GET_SETTINGS_SUCCEEDED,
ON_CANCEL,
ON_CHANGE,
SET_ERRORS,
SUBMIT_ERROR,
SUBMIT_SUCCEEDED,
} from './constants';
const initialState = fromJS({
appEnvironments: List([]),
didCheckErrors: false,
env: '',
formErrors: List([]),
initialData: Map({}),
modifiedData: Map({}),
settings: {},
submitSuccess: false,
});
function configPageReducer(state = initialState, action) {
switch (action.type) {
case GET_SETTINGS:
return state.update('env', () => action.env);
case GET_SETTINGS_SUCCEEDED:
return state
.update('appEnvironments', () => List(action.appEnvironments))
.update('didCheckErrors', (v) => v = !v)
.update('formErrors', () => List([]))
.update('initialData', () => Map(action.initialData))
.update('modifiedData', () => Map(action.initialData))
.update('settings', () => action.settings);
case ON_CANCEL:
return state
.update('didCheckErrors', (v) => v = !v)
.update('formErrors', () => List([]))
.update('modifiedData', () => state.get('initialData'));
case ON_CHANGE:
return state
.updateIn(action.keys, () => action.value);
case SET_ERRORS:
case SUBMIT_ERROR:
return state
.update('didCheckErrors', (v) => v = !v)
.update('formErrors', () => List(action.errors));
case SUBMIT_SUCCEEDED:
return state
.update('didCheckErrors', (v) => v = !v)
.update('formErrors', () => List([]))
.update('initialData', () => Map(action.data))
.update('modifiedData', () => Map(action.data))
.update('submitSuccess', (v) => v = !v);
default:
return state;
}
}
export default configPageReducer;

View File

@ -1,51 +0,0 @@
// import { LOCATION_CHANGE } from 'react-router-redux';
import { all, call, fork, put, select, takeLatest } from 'redux-saga/effects';
import { request } from 'strapi-helper-plugin';
import { getSettingsSucceeded, submitSucceeded } from './actions';
import { GET_SETTINGS, SUBMIT } from './constants';
import { makeSelectEnv, makeSelectModifiedData } from './selectors';
export function* settingsGet(action) {
try {
const requestURL = `/email/settings/${action.env}`;
const response = yield all([
call(request, requestURL, { method: 'GET' }),
call(request, '/email/environments', { method: 'GET' }),
]);
yield put(getSettingsSucceeded(response[0], response[1].environments));
} catch (err) {
strapi.notification.error('notification.error');
}
}
export function* submit() {
try {
const env = yield select(makeSelectEnv());
let body = yield select(makeSelectModifiedData());
if (body.provider === 'local') {
body = {
enabled: body.enabled,
provider: 'local',
sizeLimit: body.sizeLimit,
};
}
const requestURL = `/email/settings/${env}`;
yield call(request, requestURL, { method: 'PUT', body });
// Update reducer with optimisticResponse
strapi.notification.success('email.notification.config.success');
yield put(submitSucceeded(body));
} catch (err) {
strapi.notification.error('notification.error');
// TODO handle error PUT
}
}
function* defaultSaga() {
yield fork(takeLatest, GET_SETTINGS, settingsGet);
yield fork(takeLatest, SUBMIT, submit);
}
export default defaultSaga;

View File

@ -1,32 +0,0 @@
import { createSelector } from 'reselect';
import pluginId from '../../pluginId';
/**
* Direct selector to the configPage state domain
*/
const selectConfigPageDomain = () => state => state.get(`${pluginId}_configPage`);
/**
* Default selector used by ConfigPage
*/
const selectConfigPage = () => createSelector(
selectConfigPageDomain(),
(substate) => substate.toJS(),
);
const makeSelectEnv = () => createSelector(
selectConfigPageDomain(),
(substate) => substate.get('env'),
);
const makeSelectModifiedData = () => createSelector(
selectConfigPageDomain(),
(substate) => substate.get('modifiedData').toJS(),
);
export default selectConfigPage;
export {
makeSelectEnv,
makeSelectModifiedData,
};

View File

@ -1,28 +0,0 @@
/**
*
* Initializer
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import pluginId from '../../pluginId';
class Initializer extends React.PureComponent {
// eslint-disable-line react/prefer-stateless-function
componentDidMount() {
// Emit the event 'pluginReady'
this.props.updatePlugin(pluginId, 'isReady', true);
}
render() {
return null;
}
}
Initializer.propTypes = {
updatePlugin: PropTypes.func.isRequired,
};
export default Initializer;

View File

@ -1,19 +0,0 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import Initializer from '../index';
describe('<Initializer />', () => {
it('Should not crash', () => {
const updatePlugin = jest.fn();
shallow(<Initializer updatePlugin={updatePlugin} />);
});
it('should call the updatePlugin props when mounted', () => {
const updatePlugin = jest.fn();
const wrapper = mount(<Initializer updatePlugin={updatePlugin} />);
expect(wrapper.prop('updatePlugin')).toHaveBeenCalledWith('email', 'isReady', true);
});
});

View File

@ -8,10 +8,6 @@
import pluginPkg from '../../package.json';
import pluginId from './pluginId';
import pluginLogo from './assets/images/logo.svg';
import App from './containers/App';
import Initializer from './containers/Initializer';
import lifecycles from './lifecycles';
import reducers from './reducers';
import trads from './translations';
export default strapi => {
@ -23,18 +19,18 @@ export default strapi => {
description: pluginDescription,
icon: pluginPkg.strapi.icon,
id: pluginId,
initializer: Initializer,
isReady: true,
initializer: () => null,
injectedComponents: [],
isRequired: pluginPkg.strapi.required || false,
layout: null,
lifecycles,
lifecycles: () => {},
leftMenuLinks: [],
leftMenuSections: [],
mainComponent: App,
mainComponent: null,
name: pluginPkg.strapi.name,
pluginLogo,
preventComponentRendering: false,
reducers,
trads,
};

View File

@ -1,13 +0,0 @@
/*
*
* SET THE HOOKS TO ENABLE THE MAGIC OF STRAPI.
* -------------------------------------------
*
* Secure, customise and enhance your project by setting
* the hooks via this file.
*
*/
function lifecycles() {}
export default lifecycles;

View File

@ -1,8 +0,0 @@
import configPageReducer from './containers/ConfigPage/reducer';
import pluginId from './pluginId';
const reducers = {
[`${pluginId}_configPage`]: configPageReducer,
};
export default reducers;

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Nastavení zásuvný modul odesílání e-mailů",
"ConfigPage.title": "E-mail - Nastavení",
"EditForm.Input.number.label": "Maximální povolená velikost (v MB)",
"EditForm.Input.select.inputDescription": "E-maily mohou být odeslány výchozím (Sendmail) nebo externím poskytovatelem.",
"EditForm.Input.select.label": "Poskytovatelé",
"EditForm.Input.toggle.label": "Povolit odesílání e-mailů",
"notification.config.success": "Nastavení bylo uloženo",
"plugin.description.long": "Odeslat e-maily.",
"plugin.description.short": "Odeslat e-maily."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "E-Mail-Plugin konfigurieren",
"ConfigPage.title": "E-Mail - Einstellungen",
"EditForm.Input.number.label": "Maximal zulässige Größe (in MB)",
"EditForm.Input.select.inputDescription": "E-Mails können mit dem Standardanbieter (Sendmail) oder einem externen Anbieter versendet werden",
"EditForm.Input.select.label": "Anbieter",
"EditForm.Input.toggle.label": "E-Mail-Versand aktivieren",
"notification.config.success": "Die Einstellungen wurden aktualisiert",
"plugin.description.long": "Zum Versand von E-Mails.",
"plugin.description.short": "Zum Versand von E-Mails."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Configure the email plugin",
"ConfigPage.title": "Email - Settings",
"EditForm.Input.number.label": "Maximum size allowed (in MB)",
"EditForm.Input.select.inputDescription": "Emails can be sent with the default provider (Sendmail) or an external provider",
"EditForm.Input.select.label": "Providers",
"EditForm.Input.toggle.label": "Enable email send",
"notification.config.success": "The settings has been updated",
"plugin.description.long": "Send emails.",
"plugin.description.short": "Send emails."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Configurar el plugin de correo electrónico",
"ConfigPage.title": "Correo electrónico - Configuración",
"EditForm.Input.number.label": "Tamaño máximo permitido (en MB)",
"EditForm.Input.select.inputDescription": "Los correos electrónicos se pueden enviar con el proveedor predeterminado (Sendmail) o con un proveedor externo.",
"EditForm.Input.select.label": "Proveedores",
"EditForm.Input.toggle.label": "Habilitar envío de correo electrónico",
"notification.config.success": "Se ha actualizado la configuración",
"plugin.description.long": "Enviar correos electrónicos.",
"plugin.description.short": "Enviar correos electrónicos."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Configurer le plugin email",
"ConfigPage.title": "E-mail - Paramètres",
"EditForm.Input.number.label": "Taille maximale autorisée (en MB)",
"EditForm.Input.select.inputDescription": "Les e-mails peuvent être envoyés avec le fournisseur par défaut (Sendmail) ou un fournisseur externe.",
"EditForm.Input.select.label": "Fournisseurs",
"EditForm.Input.toggle.label": "Activer l'envoi d'e-mails",
"notification.config.success": "Les paramètres ont été mis à jour.",
"plugin.description.long": "Envoyez des emails",
"plugin.description.short": "Envoyez des emails"
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Configura il plugin Email",
"ConfigPage.title": "Email - Impostazioni",
"EditForm.Input.number.label": "Dimensione massima consentita (in MB)",
"EditForm.Input.select.inputDescription": "Le e-mail possono essere inviate con il provider predefinito (Sendmail) o un provider esterno",
"EditForm.Input.select.label": "Providers",
"EditForm.Input.toggle.label": "Abilita invio email",
"notification.config.success": "Le impostazioni sono state aggiornate",
"plugin.description.long": "Invia le email.",
"plugin.description.short": "Invia le email."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Eメールプラグインを設定する",
"ConfigPage.title": "Eメール - 設定",
"EditForm.Input.number.label": "許可される最大サイズMB単位",
"EditForm.Input.select.inputDescription": "電子メールは、デフォルトのプロバイダSendmailまたは外部プロバイダ",
"EditForm.Input.select.label": "プロバイダー",
"EditForm.Input.toggle.label": "メール送信を有効にする",
"notification.config.success": "設定が更新されました",
"plugin.description.long": "メールを送る",
"plugin.description.short": "メールを送る"
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "이메일 플러그인을 설정합니다.",
"ConfigPage.title": "이메일 설정",
"EditForm.Input.number.label": "최대 허용 크기(MB)",
"EditForm.Input.select.inputDescription": "이메일을 기본 프로바이더(Sendmail) 또는 외부 프로바이더를 통해 전동합니다.",
"EditForm.Input.select.label": "프로바이더(Providers)",
"EditForm.Input.toggle.label": "이메일 전송 허용",
"notification.config.success": "설정을 업데이트 했습니다.",
"plugin.description.long": "이메일을 전송합니다.",
"plugin.description.short": "이메일을 전송합니다."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Configureer de e-mail extensie",
"ConfigPage.title": "E-mail - Instellingen",
"EditForm.Input.number.label": "Maximum grootte toegestaan (in MB)",
"EditForm.Input.select.inputDescription": "E-mails kunnen worden verstuurd via de standaard leverancier (Sendmail) of via een externe leverancier",
"EditForm.Input.select.label": "Leveranciers",
"EditForm.Input.toggle.label": "E-mail versturen inschakelen",
"notification.config.success": "De instellingen zijn opgeslagen.",
"plugin.description.long": "Verstuur e-mails.",
"plugin.description.short": "Verstuur e-mails."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Skonfiguruj plugin email",
"ConfigPage.title": "Email - Ustawienia",
"EditForm.Input.number.label": "Maksymalny dozwolony rozmiar (w MB)",
"EditForm.Input.select.inputDescription": "E-maile mogą być wysyłane z wykorzystaniem domyślnego (Sendmail) albo zewnętrznego dostawcy",
"EditForm.Input.select.label": "Dostawcy",
"EditForm.Input.toggle.label": "Włącz wysyłkę e-maili",
"notification.config.success": "Ustawienia zostały zaktualizowane",
"plugin.description.long": "Wysyłaj E-maile",
"plugin.description.short": "Wysyłaj E-maile"
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Configure a extensão do email",
"ConfigPage.title": "E-mail - Definições",
"EditForm.Input.number.label": "Tamanho máximo permitido (em MB)",
"EditForm.Input.select.inputDescription": "Os emails podem ser enviados com o provedor predefinido (Sendmail) ou por um provedor externo",
"EditForm.Input.select.label": "Provedores",
"EditForm.Input.toggle.label": "Ativar envio de email",
"notification.config.success": "As configurações foram atualizadas",
"plugin.description.long": "Enviar emails.",
"plugin.description.short": "Enviar emails."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Configure a extensão do email",
"ConfigPage.title": "Email - Definições",
"EditForm.Input.number.label": "Tamanho máximo permitido (em MB)",
"EditForm.Input.select.inputDescription": "Os emails podem ser enviados com o provedor predefinido (Sendmail) ou por um provedor externo",
"EditForm.Input.select.label": "Provedores",
"EditForm.Input.toggle.label": "Activar envio de email",
"notification.config.success": "As configurações foram actualizadas",
"plugin.description.long": "Enviar emails.",
"plugin.description.short": "Enviar emails."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Настройка плагина email",
"ConfigPage.title": "Email - Настройки",
"EditForm.Input.number.label": "Максимально допустимый размер (в МБ)",
"EditForm.Input.select.inputDescription": "Письма могут быть отправлены стандартным способом (Sendmail) или с помощью внешних провайдеров",
"EditForm.Input.select.label": "Провайдеры",
"EditForm.Input.toggle.label": "Активировать отправку писем",
"notification.config.success": "Настройки успешно обновлены",
"plugin.description.long": "Отправка почты.",
"plugin.description.short": "Отправка почты."
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Nastavenia odosielania e-mailov",
"ConfigPage.title": "Email - Nastavenia",
"EditForm.Input.number.label": "Maximálna povolená veľkosť (v MB)",
"EditForm.Input.select.inputDescription": "E-maily môžu byť posielané cez Sendmail alebo externého poskytovateľa",
"EditForm.Input.select.label": "Poskytovatelia",
"EditForm.Input.toggle.label": "Povoliť odosielanie emailov",
"notification.config.success": "Nastavenia boli upravené",
"plugin.description.long": "Posielanie e-mailov.",
"plugin.description.short": "Posielanie e-mailov."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "E-posta eklentisini yapılandırma",
"ConfigPage.title": "E-posta - Ayarlar",
"EditForm.Input.number.label": "İzin verilen maksimum boyut (MB cinsinden)",
"EditForm.Input.select.inputDescription": "E-postalar varsayılan sağlayıcı (Sendmail) veya harici bir sağlayıcıyla gönderilebilir",
"EditForm.Input.select.label": "Sağlayıcıları",
"EditForm.Input.toggle.label": "E-posta gönderimini etkinleştir",
"notification.config.success": "Ayarlar güncellendi",
"plugin.description.long": "E-posta gönder.",
"plugin.description.short": "E-posta gönder."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "Cấu hình email plugin",
"ConfigPage.title": "Email - Các cài đặt",
"EditForm.Input.number.label": "Kích thước tối đa được phép (MB)",
"EditForm.Input.select.inputDescription": "Các Email có thể được gửi với nhà cung cấp mặc định (Sendmail) hoặc là nhà cung cấp bên ngoài",
"EditForm.Input.select.label": "Các nhà cung cấp",
"EditForm.Input.toggle.label": "Kích hoạt gửi email",
"notification.config.success": "Các cài đặt đã được cập nhật",
"plugin.description.long": "Gửi các email.",
"plugin.description.short": "Gửi các email."
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "配置电子邮件插件",
"ConfigPage.title": "电子邮件 - 设置",
"EditForm.Input.number.label": "最大文件限制 (单位:MB)",
"EditForm.Input.select.inputDescription": "可以使用默认提供商Sendmail或外部提供商发送电子邮件",
"EditForm.Input.select.label": "提供商",
"EditForm.Input.toggle.label": "启用电子邮件发送",
"notification.config.success": "设置已更新",
"plugin.description.long": "发送电子邮件。",
"plugin.description.short": "发送电子邮件。"
}
}

View File

@ -1,11 +1,4 @@
{
"ConfigPage.description": "設定郵件擴充功能",
"ConfigPage.title": "郵件 - 設定",
"EditForm.Input.number.label": "最大大小 (MB)",
"EditForm.Input.select.inputDescription": "可以使用預設 (Sendmail) 或其他套件寄送郵件",
"EditForm.Input.select.label": "套件",
"EditForm.Input.toggle.label": "啟動寄信功能",
"notification.config.success": "設定已經更新",
"plugin.description.long": "寄送電子郵件",
"plugin.description.short": "寄送電子郵件"
}
}

View File

@ -1,44 +1,21 @@
'use strict';
/**
* An asynchronous bootstrap function that runs before
* your application gets started.
*
* This gives you an opportunity to set up your data model,
* run jobs, or perform some special logic.
*/
const _ = require('lodash');
module.exports = async () => {
// set plugin store
const pluginStore = strapi.store({
environment: strapi.config.environment,
type: 'plugin',
name: 'email',
});
strapi.plugins.email.config.providers = [];
const installedProviders = Object.keys(strapi.config.info.dependencies)
.filter(d => d.includes('strapi-provider-email-'))
.concat('strapi-provider-email-sendmail');
for (let installedProvider of _.uniq(installedProviders)) {
strapi.plugins.email.config.providers.push(require(installedProvider));
}
// if provider config does not exist set one by default
const config = await pluginStore.get({ key: 'provider' });
if (!config) {
const provider = _.find(strapi.plugins.email.config.providers, {
provider: 'sendmail',
});
const value = _.assign({}, provider, {
// TODO: set other default settings here
});
await pluginStore.set({ key: 'provider', value });
const createProvider = emailConfig => {
const providerName = _.toLower(emailConfig.provider);
let provider;
try {
provider = require(`strapi-provider-email-${providerName}`);
} catch (err) {
throw new Error(
`The provider package isn't installed. Please run \`npm install strapi-provider-email-${providerName}\` --save`
);
}
return provider.init(emailConfig.providerOptions, emailConfig.settings);
};
module.exports = async () => {
const emailConfig = _.get(strapi.plugins, 'email.config', {});
strapi.plugins.email.provider = createProvider(emailConfig);
};

View File

@ -12,30 +12,6 @@
"name": "Email"
}
}
},
{
"method": "GET",
"path": "/environments",
"handler": "Email.getEnvironments",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/settings/:environment",
"handler": "Email.getSettings",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/settings/:environment",
"handler": "Email.updateSettings",
"config": {
"policies": []
}
}
]
}

View File

@ -0,0 +1,7 @@
module.exports = {
provider: 'sendmail',
providerOptions: {},
settings: {
defaultFrom: 'Strapi <no-reply@strapi.io>',
},
};

View File

@ -7,69 +7,10 @@
*/
module.exports = {
send: async ctx => {
// Retrieve provider configuration.
const config = await strapi
.store({
environment: strapi.config.environment,
type: 'plugin',
name: 'email',
})
.get({ key: 'provider' });
// Verify if the file email is enable.
if (config.enabled === false) {
strapi.log.error('Email is disabled');
return ctx.badRequest(null, [
{
messages: [{ id: 'Email.status.disabled', message: 'Emails disabled' }],
},
]);
}
// Something is wrong
if (ctx.status === 400) {
return;
}
let options = ctx.request.body;
await strapi.plugins.email.services.email.send(options, config);
await strapi.plugins.email.services.email.send(options);
// Send 200 `ok`
ctx.send({});
},
getEnvironments: async ctx => {
const envs = ['development', 'staging', 'production'];
ctx.send({
environments: envs.map(env => ({
name: env,
active: env === strapi.config.environment,
})),
});
},
getSettings: async ctx => {
let config = await strapi.plugins.email.services.email.getProviderConfig(
ctx.params.environment
);
ctx.send({
providers: strapi.plugins.email.config.providers,
config,
});
},
updateSettings: async ctx => {
await strapi
.store({
environment: ctx.params.environment,
type: 'plugin',
name: 'email',
})
.set({ key: 'provider', value: ctx.request.body });
ctx.send({ ok: true });
},
};

View File

@ -3,7 +3,7 @@
"/email/": {
"post": {
"deprecated": false,
"description": "Send an email using the provider defined through the dashboard",
"description": "Send an email",
"requestBody": {
"content": {
"application/json": {
@ -17,11 +17,22 @@
"to": {
"type": "string",
"format": "email",
"example": "user@example.com"
"example": "user1@example.com"
},
"reply_to": {
"cc": {
"type": "string",
"format": "email",
"example": "user2@example.com"
},
"bcc": {
"type": "string",
"format": "email",
"example": "user3@example.com"
},
"replyTo": {
"type": "string",
"format": "email"
"example": "user4@example.com"
},
"subject": {
"type": "string",
@ -53,4 +64,4 @@
"name": "Email"
}
]
}
}

View File

@ -1,72 +1,12 @@
'use strict';
/**
* Email.js service
*
* @description: A set of functions similar to controller's actions to avoid code duplication.
*/
const _ = require('lodash');
const createDefaultEnvConfig = async env => {
const pluginStore = strapi.store({
environment: env,
type: 'plugin',
name: 'email',
});
const provider = _.find(strapi.plugins.email.config.providers, {
provider: 'sendmail',
});
const value = _.assign({}, provider, {});
await pluginStore.set({ key: 'provider', value });
return await strapi
.store({
environment: env,
type: 'plugin',
name: 'email',
})
.get({ key: 'provider' });
};
const getProviderConfig = async env => {
let config = await strapi
.store({
environment: env,
type: 'plugin',
name: 'email',
})
.get({ key: 'provider' });
if (!config) {
config = await createDefaultEnvConfig(env);
}
return config;
const getProviderConfig = () => {
return strapi.plugins.email.config;
};
module.exports = {
getProviderConfig,
async send(options, config) {
// Get email provider settings to configure the provider to use.
if (!config) {
config = await getProviderConfig(strapi.config.environment);
}
const provider = _.find(strapi.plugins.email.config.providers, {
provider: config.provider,
});
if (!provider) {
throw new Error(
`The provider package isn't installed. Please run \`npm install strapi-provider-email-${config.provider}\``
);
}
const actions = await provider.init(config);
// Execute email function of the provider for all files.
return actions.send(options);
async send(options) {
return strapi.plugins.email.provider.send(options);
},
};

View File

@ -9,3 +9,50 @@
- [Strapi website](http://strapi.io/)
- [Strapi community on Slack](http://slack.strapi.io)
- [Strapi news on Twitter](https://twitter.com/strapijs)
## Prerequisites
You need to have the plugin `strapi-plugin-email` installed in you Strapi project.
## Installation
```bash
# using yarn
yarn add strapi-provider-email-amazon-ses
# using npm
npm install strapi-provider-email-amazon-ses --save
```
## Configuration
| Variable | Type | Description | Required | Default |
| ----------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------- | -------- | --------- |
| provider | string | The name of the provider you use | yes | |
| providerOptions | object | Will be directly given to `createClient` function. Please refer to [node-ses](https://www.npmjs.com/package/node-ses) doc. | yes | |
| settings | object | Settings | no | {} |
| settings.defaultFrom | string | Default sender mail address | no | undefined |
| settings.defaultReplyTo | string \| array<string> | Default address or addresses the receiver is asked to reply to | no | undefined |
### Example
**Path -** `config/plugins.js`
```js
module.exports = ({ env }) => ({
// ...
email: {
provider: 'amazon-ses',
providerOptions: {
key: env('AWS_SES_KEY'),
secret: env('AWS_SES_SECRET'),
amazon: 'https://email.us-east-1.amazonaws.com',
},
settings: {
defaultFrom: 'myemail@protonmail.com',
defaultReplyTo: 'myemail@protonmail.com',
},
},
// ...
});
```

View File

@ -1,68 +1,30 @@
'use strict';
/**
* Module dependencies
*/
/* eslint-disable prefer-template */
// Public node modules.
const _ = require('lodash');
const nodeSES = require('node-ses');
const { removeUndefined } = require('strapi-utils');
/* eslint-disable no-unused-vars */
module.exports = {
provider: 'amazon-ses',
name: 'Amazon SES',
auth: {
amazon_ses_default_from: {
label: 'Default From',
type: 'text',
},
amazon_ses_default_replyto: {
label: 'Default Reply-To',
type: 'text',
},
amazon_ses_api_key: {
label: 'Amazon Access key ID',
type: 'text',
},
amazon_ses_secret: {
label: 'Amazon Secret access key',
type: 'text',
},
amazon_ses_endpoint: {
label: 'Amazon end-point uri',
type: 'text',
},
},
init: config => {
var client = nodeSES.createClient({
key: config.amazon_ses_api_key,
secret: config.amazon_ses_secret,
amazon: config.amazon_ses_endpoint,
});
init: (providerOptions = {}, settings = {}) => {
var client = nodeSES.createClient({ ...providerOptions });
return {
send: options => {
return new Promise((resolve, reject) => {
// Default values.
options = _.isObject(options) ? options : {};
options.from = config.amazon_ses_default_from || options.from;
options.replyTo = config.amazon_ses_default_replyto || options.replyTo;
options.text = options.text || options.html;
options.html = options.html || options.text;
const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;
let msg = {
from: options.from,
to: options.to,
replyTo: options.replyTo,
subject: options.subject,
altText: options.text,
message: options.html,
from: from || settings.defaultFrom,
to,
cc,
bcc,
replyTo: replyTo || settings.defaultReplyTo,
subject,
text,
html,
...rest,
};
client.sendEmail(msg, function(err) {
client.sendEmail(removeUndefined(msg), function(err) {
if (err) {
reject([{ messages: [{ id: 'Auth.form.error.email.invalid' }] }]);
} else {

View File

@ -14,8 +14,8 @@
},
"main": "./lib",
"dependencies": {
"lodash": "^4.17.11",
"node-ses": "^3.0.0"
"node-ses": "^3.0.0",
"strapi-utils": "3.0.0-beta.20.3"
},
"author": {
"email": "nikolay@tsenkov.net",

View File

@ -9,3 +9,48 @@
- [Strapi website](http://strapi.io/)
- [Strapi community on Slack](http://slack.strapi.io)
- [Strapi news on Twitter](https://twitter.com/strapijs)
## Prerequisites
You need to have the plugin `strapi-plugin-email` installed in you Strapi project.
## Installation
```bash
# using yarn
yarn add strapi-provider-email-mailgun
# using npm
npm install strapi-provider-email-mailgun --save
```
## Configuration
| Variable | Type | Description | Required | Default |
| ----------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------- | --------- |
| provider | string | The name of the provider you use | yes | |
| providerOptions | object | Will be directly given to the `require('mailgun-js')`. Please refer to [mailgun-js](https://www.npmjs.com/package/mailgun-js) doc. | yes | |
| settings | object | Settings | no | {} |
| settings.defaultFrom | string | Default sender mail address | no | undefined |
| settings.defaultReplyTo | string \| array<string> | Default address or addresses the receiver is asked to reply to | no | undefined |
### Example
**Path -** `config/plugins.js`
```js
module.exports = ({ env }) => ({
// ...
email: {
provider: 'mailgun',
providerOptions: {
apiKey: env('MAILGUN_API_KEY'),
},
settings: {
defaultFrom: 'myemail@protonmail.com',
defaultReplyTo: 'myemail@protonmail.com',
},
},
// ...
});
```

View File

@ -1,69 +1,33 @@
'use strict';
/**
* Module dependencies
*/
/* eslint-disable prefer-template */
// Public node modules.
const isObject = require('lodash/isObject');
const mailgunFactory = require('mailgun-js');
const { removeUndefined } = require('strapi-utils');
/* eslint-disable no-unused-vars */
module.exports = {
provider: 'mailgun',
name: 'Mailgun',
auth: {
mailgun_default_from: {
label: 'Mailgun Default From',
type: 'text',
},
mailgun_default_replyto: {
label: 'Mailgun Default Reply-To',
type: 'text',
},
mailgun_api_key: {
label: 'Mailgun API Key',
type: 'text',
},
mailgun_api_host: {
label: 'Mailgun API Host',
type: 'text',
},
mailgun_domain: {
label: 'Mailgun Domain',
type: 'text',
},
},
init: config => {
init: (providerOptions = {}, settings = {}) => {
const mailgun = mailgunFactory({
apiKey: config.mailgun_api_key,
host: config.mailgun_api_host,
domain: config.mailgun_domain,
mute: false,
...providerOptions,
});
return {
send: options => {
return new Promise((resolve, reject) => {
// Default values.
options = isObject(options) ? options : {};
const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;
let msg = {
from: options.from || config.mailgun_default_from,
to: options.to,
subject: options.subject,
...(options.text && { text: options.text }),
...(options.html && { html: options.html }),
...(options.template && { template: options.template }),
...(options['h:X-Mailgun-Variables'] && {
'h:X-Mailgun-Variables': options['h:X-Mailgun-Variables'],
}),
...(options.attachment && { attachment: options.attachment }),
from: from || settings.defaultFrom,
to,
cc,
bcc,
'h:Reply-To': replyTo || settings.defaultReplyTo,
subject,
text,
html,
...rest,
};
msg['h:Reply-To'] = options.replyTo || config.mailgun_default_replyto;
mailgun.messages().send(msg, function(err) {
mailgun.messages().send(removeUndefined(msg), function(err) {
if (err) {
reject([{ messages: [{ id: 'Auth.form.error.email.invalid' }] }]);
} else {

View File

@ -13,8 +13,8 @@
},
"main": "./lib",
"dependencies": {
"lodash": "^4.17.11",
"mailgun-js": "0.22.0"
"mailgun-js": "0.22.0",
"strapi-utils": "3.0.0-beta.20.3"
},
"strapi": {
"isProvider": true

View File

@ -1,4 +1,4 @@
# strapi-provider-email-sendmail
# strapi-provider-email-sendgrid
## Resources
@ -9,3 +9,49 @@
- [Strapi website](http://strapi.io/)
- [Strapi community on Slack](http://slack.strapi.io)
- [Strapi news on Twitter](https://twitter.com/strapijs)
## Prerequisites
You need to have the plugin `strapi-plugin-email` installed in you Strapi project.
## Installation
```bash
# using yarn
yarn add strapi-provider-email-sendgrid
# using npm
npm install strapi-provider-email-sendgrid --save
```
## Configuration
| Variable | Type | Description | Required | Default |
| ----------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------- | -------- | --------- |
| provider | string | The name of the provider you use | yes | |
| providerOptions | object | Provider options | yes | |
| providerOptions.apiKey | object | Api key given to the function setApiKey. Please refer to [@sendgrid/mail](https://www.npmjs.com/package/@sendgrid/mail) | yes | |
| settings | object | Settings | no | {} |
| settings.defaultFrom | string | Default sender mail address | no | undefined |
| settings.defaultReplyTo | string \| array<string> | Default address or addresses the receiver is asked to reply to | no | undefined |
### Example
**Path -** `config/plugins.js`
```js
module.exports = ({ env }) => ({
// ...
email: {
provider: 'sendgrid',
providerOptions: {
apiKey: env('SENDGRID_API_KEY'),
},
settings: {
defaultFrom: 'myemail@protonmail.com',
defaultReplyTo: 'myemail@protonmail.com',
},
},
// ...
});
```

View File

@ -1,59 +1,30 @@
'use strict';
/**
* Module dependencies
*/
/* eslint-disable prefer-template */
// Public node modules.
const _ = require('lodash');
const sendgrid = require('@sendgrid/mail');
const { removeUndefined } = require('strapi-utils');
/* eslint-disable no-unused-vars */
module.exports = {
provider: 'sendgrid',
name: 'Sendgrid',
auth: {
sendgrid_default_from: {
label: 'Sendgrid Default From',
type: 'text',
},
sendgrid_default_replyto: {
label: 'Sendgrid Default Reply-To',
type: 'text',
},
sendgrid_api_key: {
label: 'Sendgrid API Key',
type: 'text',
},
},
init: config => {
sendgrid.setApiKey(config.sendgrid_api_key);
init: (providerOptions = {}, settings = {}) => {
sendgrid.setApiKey(providerOptions.apiKey);
return {
send: options => {
return new Promise((resolve, reject) => {
// Default values.
options = _.isObject(options) ? options : {};
options.from = options.from || config.sendgrid_default_from;
options.replyTo = options.replyTo || config.sendgrid_default_replyto;
options.text = options.text || options.html;
options.html = options.html || options.text;
const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;
let msg = {
from: options.from,
to: options.to,
replyTo: options.replyTo,
subject: options.subject,
text: options.text,
html: options.html,
templateId: options.templateId,
dynamic_template_data: options.dynamic_template_data,
sendAt: options.sendAt,
batchId: options.batchId,
from: from || settings.defaultFrom,
to,
cc,
bcc,
replyTo: replyTo || settings.defaultReplyTo,
subject,
text,
html,
...rest,
};
sendgrid.send(msg, function(err) {
sendgrid.send(removeUndefined(msg), function(err) {
if (err) {
reject([{ messages: [{ id: 'Auth.form.error.email.invalid' }] }]);
} else {

View File

@ -14,7 +14,7 @@
"main": "./lib",
"dependencies": {
"@sendgrid/mail": "6.4.0",
"lodash": "^4.17.11"
"strapi-utils": "3.0.0-beta.20.3"
},
"strapi": {
"isProvider": true

View File

@ -9,3 +9,45 @@
- [Strapi website](http://strapi.io/)
- [Strapi community on Slack](http://slack.strapi.io)
- [Strapi news on Twitter](https://twitter.com/strapijs)
## Prerequisites
You need to have the plugin `strapi-plugin-email` installed in you Strapi project.
## Installation
```bash
# using yarn
yarn add strapi-provider-email-sendmail
# using npm
npm install strapi-provider-email-sendmail --save
```
## Configuration
| Variable | Type | Description | Required | Default |
| ----------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------ | -------- | --------- |
| provider | string | The name of the provider you use | yes | |
| providerOptions | object | Will be directly given to `require('sendmail')`. Please refer to [sendmail](https://www.npmjs.com/package/sendmail) doc. | no | {} |
| settings | object | Settings | no | {} |
| settings.defaultFrom | string | Default sender mail address | no | undefined |
| settings.defaultReplyTo | string \| array<string> | Default address or addresses the receiver is asked to reply to | no | undefined |
### Example
**Path -** `config/plugins.js`
```js
module.exports = ({ env }) => ({
// ...
email: {
provider: 'sendmail',
settings: {
defaultFrom: 'myemail@protonmail.com',
defaultReplyTo: 'myemail@protonmail.com',
},
},
// ...
});
```

View File

@ -1,58 +1,38 @@
'use strict';
/**
* Module dependencies
*/
const sendmailFactory = require('sendmail');
const { removeUndefined } = require('strapi-utils');
// Public node modules.
const _ = require('lodash');
const sendmail = require('sendmail')({
silent: true,
});
/* eslint-disable no-unused-vars */
module.exports = {
provider: 'sendmail',
name: 'Sendmail',
auth: {
sendmail_default_from: {
label: 'Sendmail Default From',
type: 'text',
},
sendmail_default_replyto: {
label: 'Sendmail Default Reply-To',
type: 'text',
},
},
init: config => {
init: (providerOptions = {}, settings = {}) => {
const sendmail = sendmailFactory({
silent: true,
...providerOptions,
});
return {
send: options => {
return new Promise((resolve, reject) => {
// Default values.
options = _.isObject(options) ? options : {};
options.from = options.from || config.sendmail_default_from;
options.replyTo = options.replyTo || config.sendmail_default_replyto;
options.text = options.text || options.html;
options.html = options.html || options.text;
const { from, to, cc, bcc, replyTo, subject, text, html, ...rest } = options;
sendmail(
{
from: options.from,
to: options.to,
replyTo: options.replyTo,
subject: options.subject,
text: options.text,
html: options.html,
attachments: options.attachments,
},
function(err) {
if (err) {
reject([{ messages: [{ id: 'Auth.form.error.email.invalid' }] }]);
} else {
resolve();
}
let msg = {
from: from || settings.defaultFrom,
to,
cc,
bcc,
replyTo: replyTo || settings.defaultReplyTo,
subject,
text,
html,
...rest,
};
sendmail(removeUndefined(msg), err => {
if (err) {
reject([{ messages: [{ id: 'Auth.form.error.email.invalid' }] }]);
} else {
resolve();
}
);
});
});
},
};

View File

@ -12,8 +12,8 @@
},
"main": "./lib",
"dependencies": {
"lodash": "^4.17.11",
"sendmail": "^1.2.0"
"sendmail": "^1.6.1",
"strapi-utils": "3.0.0-beta.20.3"
},
"strapi": {
"isProvider": true

View File

@ -21,6 +21,7 @@ const {
getCommonBeginning,
escapeQuery,
} = require('./stringFormatting');
const { removeUndefined } = require('./objectFormatting');
const { getConfigUrls } = require('./config');
module.exports = {
@ -41,4 +42,5 @@ module.exports = {
getCommonBeginning,
getConfigUrls,
escapeQuery,
removeUndefined,
};

View File

@ -0,0 +1,9 @@
'use strict';
const _ = require('lodash');
const removeUndefined = obj => _.pickBy(obj, value => typeof value !== 'undefined');
module.exports = {
removeUndefined,
};

View File

@ -16421,7 +16421,7 @@ send@0.17.1:
range-parser "~1.2.1"
statuses "~1.5.0"
sendmail@^1.2.0:
sendmail@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/sendmail/-/sendmail-1.6.1.tgz#6be92fb4be70d1d9ad102030aeb1e737bd512159"
integrity sha512-lIhvnjSi5e5jL8wA1GPP6j2QVlx6JOEfmdn0QIfmuJdmXYGmJ375kcOU0NSm/34J+nypm4sa1AXrYE5w3uNIIA==