about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2018-01-18 19:17:25 +0100
committerGitHub <noreply@github.com>2018-01-18 19:17:25 +0100
commitd799921c75e7bfb83504bb79dcc1c269c91d168c (patch)
tree8150e8c3d81038ed132127d2ea1ca2a44ff73fb1
parente56404be414ff2fc7ff11171fdd2b31a0658aa11 (diff)
Replace tutorial modal with welcome e-mail (#6273)
* Remove onboarding modal

* Welcome e-mail

* Send welcome e-mail after confirmation

* Remove obsolete translations
-rw-r--r--app/javascript/images/icon_done.svg4
-rw-r--r--app/javascript/mastodon/actions/onboarding.js14
-rw-r--r--app/javascript/mastodon/containers/mastodon.js3
-rw-r--r--app/javascript/mastodon/features/ui/components/modal_root.js2
-rw-r--r--app/javascript/mastodon/features/ui/components/onboarding_modal.js318
-rw-r--r--app/javascript/mastodon/features/ui/util/async-components.js4
-rw-r--r--app/javascript/styles/mailer.scss44
-rw-r--r--app/javascript/styles/mastodon/components.scss254
-rw-r--r--app/mailers/user_mailer.rb11
-rw-r--r--app/models/user.rb1
-rw-r--r--app/views/layouts/mailer.text.erb2
-rw-r--r--app/views/user_mailer/welcome.html.haml146
-rw-r--r--app/views/user_mailer/welcome.text.erb30
-rw-r--r--config/locales/ar.yml1
-rw-r--r--config/locales/bg.yml1
-rw-r--r--config/locales/ca.yml1
-rw-r--r--config/locales/de.yml1
-rw-r--r--config/locales/en.yml20
-rw-r--r--config/locales/eo.yml1
-rw-r--r--config/locales/es.yml1
-rw-r--r--config/locales/fa.yml1
-rw-r--r--config/locales/fi.yml1
-rw-r--r--config/locales/fr.yml1
-rw-r--r--config/locales/gl.yml1
-rw-r--r--config/locales/he.yml1
-rw-r--r--config/locales/hr.yml1
-rw-r--r--config/locales/hu.yml2
-rw-r--r--config/locales/id.yml1
-rw-r--r--config/locales/io.yml1
-rw-r--r--config/locales/it.yml1
-rw-r--r--config/locales/ja.yml1
-rw-r--r--config/locales/ko.yml1
-rw-r--r--config/locales/nl.yml1
-rw-r--r--config/locales/no.yml1
-rw-r--r--config/locales/oc.yml1
-rw-r--r--config/locales/pl.yml1
-rw-r--r--config/locales/pt-BR.yml1
-rw-r--r--config/locales/pt.yml1
-rw-r--r--config/locales/ru.yml1
-rw-r--r--config/locales/sr-Latn.yml1
-rw-r--r--config/locales/sr.yml1
-rw-r--r--config/locales/sv.yml1
-rw-r--r--config/locales/th.yml1
-rw-r--r--config/locales/tr.yml1
-rw-r--r--config/locales/uk.yml1
-rw-r--r--config/locales/zh-CN.yml1
-rw-r--r--config/locales/zh-HK.yml1
-rw-r--r--config/locales/zh-TW.yml1
-rw-r--r--spec/mailers/previews/user_mailer_preview.rb5
49 files changed, 261 insertions, 632 deletions
diff --git a/app/javascript/images/icon_done.svg b/app/javascript/images/icon_done.svg
new file mode 100644
index 000000000..446af14d9
--- /dev/null
+++ b/app/javascript/images/icon_done.svg
@@ -0,0 +1,4 @@
+<svg fill="#FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
+    <path d="M0 0h24v24H0z" fill="none"/>
+    <path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/>
+</svg>
\ No newline at end of file
diff --git a/app/javascript/mastodon/actions/onboarding.js b/app/javascript/mastodon/actions/onboarding.js
deleted file mode 100644
index a161c50ef..000000000
--- a/app/javascript/mastodon/actions/onboarding.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { openModal } from './modal';
-import { changeSetting, saveSettings } from './settings';
-
-export function showOnboardingOnce() {
-  return (dispatch, getState) => {
-    const alreadySeen = getState().getIn(['settings', 'onboarded']);
-
-    if (!alreadySeen) {
-      dispatch(openModal('ONBOARDING'));
-      dispatch(changeSetting(['onboarded'], true));
-      dispatch(saveSettings());
-    }
-  };
-};
diff --git a/app/javascript/mastodon/containers/mastodon.js b/app/javascript/mastodon/containers/mastodon.js
index d1710445b..8ae3b727a 100644
--- a/app/javascript/mastodon/containers/mastodon.js
+++ b/app/javascript/mastodon/containers/mastodon.js
@@ -2,7 +2,6 @@ import React from 'react';
 import { Provider } from 'react-redux';
 import PropTypes from 'prop-types';
 import configureStore from '../store/configureStore';
-import { showOnboardingOnce } from '../actions/onboarding';
 import { BrowserRouter, Route } from 'react-router-dom';
 import { ScrollContext } from 'react-router-scroll-4';
 import UI from '../features/ui';
@@ -40,8 +39,6 @@ export default class Mastodon extends React.PureComponent {
       const handlerUrl = window.location.protocol + '//' + window.location.host + '/intent?uri=%s';
       window.setTimeout(() => navigator.registerProtocolHandler('web+mastodon', handlerUrl, 'Mastodon'), 5 * 60 * 1000);
     }
-
-    store.dispatch(showOnboardingOnce());
   }
 
   componentWillUnmount () {
diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js
index 5839ba40a..dbfb46ee7 100644
--- a/app/javascript/mastodon/features/ui/components/modal_root.js
+++ b/app/javascript/mastodon/features/ui/components/modal_root.js
@@ -9,7 +9,6 @@ import VideoModal from './video_modal';
 import BoostModal from './boost_modal';
 import ConfirmationModal from './confirmation_modal';
 import {
-  OnboardingModal,
   MuteModal,
   ReportModal,
   EmbedModal,
@@ -18,7 +17,6 @@ import {
 
 const MODAL_COMPONENTS = {
   'MEDIA': () => Promise.resolve({ default: MediaModal }),
-  'ONBOARDING': OnboardingModal,
   'VIDEO': () => Promise.resolve({ default: VideoModal }),
   'BOOST': () => Promise.resolve({ default: BoostModal }),
   'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
diff --git a/app/javascript/mastodon/features/ui/components/onboarding_modal.js b/app/javascript/mastodon/features/ui/components/onboarding_modal.js
deleted file mode 100644
index 54673e223..000000000
--- a/app/javascript/mastodon/features/ui/components/onboarding_modal.js
+++ /dev/null
@@ -1,318 +0,0 @@
-import React from 'react';
-import { connect } from 'react-redux';
-import PropTypes from 'prop-types';
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import ReactSwipeableViews from 'react-swipeable-views';
-import classNames from 'classnames';
-import Permalink from '../../../components/permalink';
-import ComposeForm from '../../compose/components/compose_form';
-import Search from '../../compose/components/search';
-import NavigationBar from '../../compose/components/navigation_bar';
-import ColumnHeader from './column_header';
-import { List as ImmutableList } from 'immutable';
-import { me } from '../../../initial_state';
-
-const noop = () => { };
-
-const messages = defineMessages({
-  home_title: { id: 'column.home', defaultMessage: 'Home' },
-  notifications_title: { id: 'column.notifications', defaultMessage: 'Notifications' },
-  local_title: { id: 'column.community', defaultMessage: 'Local timeline' },
-  federated_title: { id: 'column.public', defaultMessage: 'Federated timeline' },
-});
-
-const PageOne = ({ acct, domain }) => (
-  <div className='onboarding-modal__page onboarding-modal__page-one'>
-    <div style={{ flex: '0 0 auto' }}>
-      <div className='onboarding-modal__page-one__elephant-friend' />
-    </div>
-
-    <div>
-      <h1><FormattedMessage id='onboarding.page_one.welcome' defaultMessage='Welcome to Mastodon!' /></h1>
-      <p><FormattedMessage id='onboarding.page_one.federation' defaultMessage='Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.' /></p>
-      <p><FormattedMessage id='onboarding.page_one.handle' defaultMessage='You are on {domain}, so your full handle is {handle}' values={{ domain, handle: <strong>@{acct}@{domain}</strong> }} /></p>
-    </div>
-  </div>
-);
-
-PageOne.propTypes = {
-  acct: PropTypes.string.isRequired,
-  domain: PropTypes.string.isRequired,
-};
-
-const PageTwo = ({ myAccount }) => (
-  <div className='onboarding-modal__page onboarding-modal__page-two'>
-    <div className='figure non-interactive'>
-      <div className='pseudo-drawer'>
-        <NavigationBar account={myAccount} />
-      </div>
-      <ComposeForm
-        text='Awoo! #introductions'
-        suggestions={ImmutableList()}
-        mentionedDomains={[]}
-        spoiler={false}
-        onChange={noop}
-        onSubmit={noop}
-        onPaste={noop}
-        onPickEmoji={noop}
-        onChangeSpoilerText={noop}
-        onClearSuggestions={noop}
-        onFetchSuggestions={noop}
-        onSuggestionSelected={noop}
-        showSearch
-      />
-    </div>
-
-    <p><FormattedMessage id='onboarding.page_two.compose' defaultMessage='Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.' /></p>
-  </div>
-);
-
-PageTwo.propTypes = {
-  myAccount: ImmutablePropTypes.map.isRequired,
-};
-
-const PageThree = ({ myAccount }) => (
-  <div className='onboarding-modal__page onboarding-modal__page-three'>
-    <div className='figure non-interactive'>
-      <Search
-        value=''
-        onChange={noop}
-        onSubmit={noop}
-        onClear={noop}
-        onShow={noop}
-      />
-
-      <div className='pseudo-drawer'>
-        <NavigationBar account={myAccount} />
-      </div>
-    </div>
-
-    <p><FormattedMessage id='onboarding.page_three.search' defaultMessage='Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.' values={{ illustration: <Permalink to='/timelines/tag/illustration' href='/tags/illustration'>#illustration</Permalink>, introductions: <Permalink to='/timelines/tag/introductions' href='/tags/introductions'>#introductions</Permalink> }} /></p>
-    <p><FormattedMessage id='onboarding.page_three.profile' defaultMessage='Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.' /></p>
-  </div>
-);
-
-PageThree.propTypes = {
-  myAccount: ImmutablePropTypes.map.isRequired,
-};
-
-const PageFour = ({ domain, intl }) => (
-  <div className='onboarding-modal__page onboarding-modal__page-four'>
-    <div className='onboarding-modal__page-four__columns'>
-      <div className='row'>
-        <div>
-          <div className='figure non-interactive'><ColumnHeader icon='home' type={intl.formatMessage(messages.home_title)} /></div>
-          <p><FormattedMessage id='onboarding.page_four.home' defaultMessage='The home timeline shows posts from people you follow.' /></p>
-        </div>
-
-        <div>
-          <div className='figure non-interactive'><ColumnHeader icon='bell' type={intl.formatMessage(messages.notifications_title)} /></div>
-          <p><FormattedMessage id='onboarding.page_four.notifications' defaultMessage='The notifications column shows when someone interacts with you.' /></p>
-        </div>
-      </div>
-
-      <div className='row'>
-        <div>
-          <div className='figure non-interactive' style={{ marginBottom: 0 }}><ColumnHeader icon='users' type={intl.formatMessage(messages.local_title)} /></div>
-        </div>
-
-        <div>
-          <div className='figure non-interactive' style={{ marginBottom: 0 }}><ColumnHeader icon='globe' type={intl.formatMessage(messages.federated_title)} /></div>
-        </div>
-      </div>
-
-      <p><FormattedMessage id='onboarding.page_five.public_timelines' defaultMessage='The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.' values={{ domain }} /></p>
-    </div>
-  </div>
-);
-
-PageFour.propTypes = {
-  domain: PropTypes.string.isRequired,
-  intl: PropTypes.object.isRequired,
-};
-
-const PageSix = ({ admin, domain }) => {
-  let adminSection = '';
-
-  if (admin) {
-    adminSection = (
-      <p>
-        <FormattedMessage id='onboarding.page_six.admin' defaultMessage="Your instance's admin is {admin}." values={{ admin: <Permalink href={admin.get('url')} to={`/accounts/${admin.get('id')}`}>@{admin.get('acct')}</Permalink> }} />
-        <br />
-        <FormattedMessage id='onboarding.page_six.read_guidelines' defaultMessage="Please read {domain}'s {guidelines}!" values={{ domain, guidelines: <a href='/about/more' target='_blank'><FormattedMessage id='onboarding.page_six.guidelines' defaultMessage='community guidelines' /></a> }} />
-      </p>
-    );
-  }
-
-  return (
-    <div className='onboarding-modal__page onboarding-modal__page-six'>
-      <h1><FormattedMessage id='onboarding.page_six.almost_done' defaultMessage='Almost done...' /></h1>
-      {adminSection}
-      <p><FormattedMessage id='onboarding.page_six.github' defaultMessage='Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.' values={{ github: <a href='https://github.com/tootsuite/mastodon' target='_blank' rel='noopener'>GitHub</a> }} /></p>
-      <p><FormattedMessage id='onboarding.page_six.apps_available' defaultMessage='There are {apps} available for iOS, Android and other platforms.' values={{ apps: <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' target='_blank' rel='noopener'><FormattedMessage id='onboarding.page_six.various_app' defaultMessage='mobile apps' /></a> }} /></p>
-      <p><em><FormattedMessage id='onboarding.page_six.appetoot' defaultMessage='Bon Appetoot!' /></em></p>
-    </div>
-  );
-};
-
-PageSix.propTypes = {
-  admin: ImmutablePropTypes.map,
-  domain: PropTypes.string.isRequired,
-};
-
-const mapStateToProps = state => ({
-  myAccount: state.getIn(['accounts', me]),
-  admin: state.getIn(['accounts', state.getIn(['meta', 'admin'])]),
-  domain: state.getIn(['meta', 'domain']),
-});
-
-@connect(mapStateToProps)
-@injectIntl
-export default class OnboardingModal extends React.PureComponent {
-
-  static propTypes = {
-    onClose: PropTypes.func.isRequired,
-    intl: PropTypes.object.isRequired,
-    myAccount: ImmutablePropTypes.map.isRequired,
-    domain: PropTypes.string.isRequired,
-    admin: ImmutablePropTypes.map,
-  };
-
-  state = {
-    currentIndex: 0,
-  };
-
-  componentWillMount() {
-    const { myAccount, admin, domain, intl } = this.props;
-    this.pages = [
-      <PageOne acct={myAccount.get('acct')} domain={domain} />,
-      <PageTwo myAccount={myAccount} />,
-      <PageThree myAccount={myAccount} />,
-      <PageFour domain={domain} intl={intl} />,
-      <PageSix admin={admin} domain={domain} />,
-    ];
-  };
-
-  componentDidMount() {
-    window.addEventListener('keyup', this.handleKeyUp);
-  }
-
-  componentWillUnmount() {
-    window.addEventListener('keyup', this.handleKeyUp);
-  }
-
-  handleSkip = (e) => {
-    e.preventDefault();
-    this.props.onClose();
-  }
-
-  handleDot = (e) => {
-    const i = Number(e.currentTarget.getAttribute('data-index'));
-    e.preventDefault();
-    this.setState({ currentIndex: i });
-  }
-
-  handlePrev = () => {
-    this.setState(({ currentIndex }) => ({
-      currentIndex: Math.max(0, currentIndex - 1),
-    }));
-  }
-
-  handleNext = () => {
-    const { pages } = this;
-    this.setState(({ currentIndex }) => ({
-      currentIndex: Math.min(currentIndex + 1, pages.length - 1),
-    }));
-  }
-
-  handleSwipe = (index) => {
-    this.setState({ currentIndex: index });
-  }
-
-  handleKeyUp = ({ key }) => {
-    switch (key) {
-    case 'ArrowLeft':
-      this.handlePrev();
-      break;
-    case 'ArrowRight':
-      this.handleNext();
-      break;
-    }
-  }
-
-  handleClose = () => {
-    this.props.onClose();
-  }
-
-  render () {
-    const { pages } = this;
-    const { currentIndex } = this.state;
-    const hasMore = currentIndex < pages.length - 1;
-
-    const nextOrDoneBtn = hasMore ? (
-      <button
-        onClick={this.handleNext}
-        className='onboarding-modal__nav onboarding-modal__next'
-      >
-        <FormattedMessage id='onboarding.next' defaultMessage='Next' />
-      </button>
-    ) : (
-      <button
-        onClick={this.handleClose}
-        className='onboarding-modal__nav onboarding-modal__done'
-      >
-        <FormattedMessage id='onboarding.done' defaultMessage='Done' />
-      </button>
-    );
-
-    return (
-      <div className='modal-root__modal onboarding-modal'>
-        <ReactSwipeableViews index={currentIndex} onChangeIndex={this.handleSwipe} className='onboarding-modal__pager'>
-          {pages.map((page, i) => {
-            const className = classNames('onboarding-modal__page__wrapper', {
-              'onboarding-modal__page__wrapper--active': i === currentIndex,
-            });
-            return (
-              <div key={i} className={className}>{page}</div>
-            );
-          })}
-        </ReactSwipeableViews>
-
-        <div className='onboarding-modal__paginator'>
-          <div>
-            <button
-              onClick={this.handleSkip}
-              className='onboarding-modal__nav onboarding-modal__skip'
-            >
-              <FormattedMessage id='onboarding.skip' defaultMessage='Skip' />
-            </button>
-          </div>
-
-          <div className='onboarding-modal__dots'>
-            {pages.map((_, i) => {
-              const className = classNames('onboarding-modal__dot', {
-                active: i === currentIndex,
-              });
-              return (
-                <div
-                  key={`dot-${i}`}
-                  role='button'
-                  tabIndex='0'
-                  data-index={i}
-                  onClick={this.handleDot}
-                  className={className}
-                />
-              );
-            })}
-          </div>
-
-          <div>
-            {nextOrDoneBtn}
-          </div>
-        </div>
-      </div>
-    );
-  }
-
-}
diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js
index d6586680b..a03c4cefd 100644
--- a/app/javascript/mastodon/features/ui/util/async-components.js
+++ b/app/javascript/mastodon/features/ui/util/async-components.js
@@ -94,10 +94,6 @@ export function Mutes () {
   return import(/* webpackChunkName: "features/mutes" */'../../mutes');
 }
 
-export function OnboardingModal () {
-  return import(/* webpackChunkName: "modals/onboarding_modal" */'../components/onboarding_modal');
-}
-
 export function MuteModal () {
   return import(/* webpackChunkName: "modals/mute_modal" */'../components/mute_modal');
 }
diff --git a/app/javascript/styles/mailer.scss b/app/javascript/styles/mailer.scss
index e6422b2ea..b3bcc9209 100644
--- a/app/javascript/styles/mailer.scss
+++ b/app/javascript/styles/mailer.scss
@@ -228,6 +228,13 @@ h3 {
   line-height: 25px;
 }
 
+h5 {
+  font-size: 16px;
+  line-height: 21px;
+  font-weight: 700;
+  color: lighten($ui-base-color, 34%);
+}
+
 .input {
   td {
     background: darken($ui-base-color, 8%);
@@ -356,6 +363,19 @@ h3 {
       font-weight: 500 !important;
     }
   }
+
+  &.button-small {
+    td {
+      border-radius: 4px;
+      font-size: 14px;
+      padding: 8px 16px;
+
+      a {
+        padding: 5px 16px !important;
+        line-height: 26px !important;
+      }
+    }
+  }
 }
 
 .button-default {
@@ -379,6 +399,14 @@ h3 {
   padding-right: 16px;
 }
 
+.padded-bottom {
+  padding-bottom: 32px;
+}
+
+.margin-bottom {
+  margin-bottom: 20px;
+}
+
 .hero-icon {
   width: 64px;
 
@@ -463,6 +491,22 @@ h3 {
   border-top: 1px solid lighten($ui-base-color, 8%);
 }
 
+ul {
+  padding-left: 15px;
+  margin-top: 0;
+  margin-bottom: 0;
+  padding-top: 16px;
+
+  li {
+    margin-bottom: 16px;
+    color: lighten($ui-base-color, 26%);
+
+    span {
+      color: $ui-primary-color;
+    }
+  }
+}
+
 @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) {
   body {
     min-height: 1024px !important;
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 6fbecee7c..63ee06d8e 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -3303,7 +3303,6 @@
   z-index: 100;
 }
 
-.onboarding-modal,
 .error-modal,
 .embed-modal {
   background: $ui-secondary-color;
@@ -3314,26 +3313,6 @@
   flex-direction: column;
 }
 
-.onboarding-modal__pager {
-  height: 80vh;
-  width: 80vw;
-  max-width: 520px;
-  max-height: 420px;
-
-  .react-swipeable-view-container > div {
-    width: 100%;
-    height: 100%;
-    box-sizing: border-box;
-    padding: 25px;
-    display: none;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    display: flex;
-    user-select: text;
-  }
-}
-
 .error-modal__body {
   height: 80vh;
   width: 80vw;
@@ -3367,23 +3346,6 @@
   text-align: center;
 }
 
-@media screen and (max-width: 550px) {
-  .onboarding-modal {
-    width: 100%;
-    height: 100%;
-    border-radius: 0;
-  }
-
-  .onboarding-modal__pager {
-    width: 100%;
-    height: auto;
-    max-width: none;
-    max-height: none;
-    flex: 1 1 auto;
-  }
-}
-
-.onboarding-modal__paginator,
 .error-modal__footer {
   flex: 0 0 auto;
   background: darken($ui-secondary-color, 8%);
@@ -3394,7 +3356,6 @@
     min-width: 33px;
   }
 
-  .onboarding-modal__nav,
   .error-modal__nav {
     color: darken($ui-secondary-color, 34%);
     background-color: transparent;
@@ -3410,11 +3371,6 @@
     &:active {
       color: darken($ui-secondary-color, 38%);
     }
-
-    &.onboarding-modal__done,
-    &.onboarding-modal__next {
-      color: $ui-highlight-color;
-    }
   }
 }
 
@@ -3422,216 +3378,6 @@
   justify-content: center;
 }
 
-.onboarding-modal__dots {
-  flex: 1 1 auto;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.onboarding-modal__dot {
-  width: 14px;
-  height: 14px;
-  border-radius: 14px;
-  background: darken($ui-secondary-color, 16%);
-  margin: 0 3px;
-  cursor: pointer;
-
-  &:hover {
-    background: darken($ui-secondary-color, 18%);
-  }
-
-  &.active {
-    cursor: default;
-    background: darken($ui-secondary-color, 24%);
-  }
-}
-
-.onboarding-modal__page__wrapper {
-  pointer-events: none;
-
-  &.onboarding-modal__page__wrapper--active {
-    pointer-events: auto;
-  }
-}
-
-.onboarding-modal__page {
-  cursor: default;
-  line-height: 21px;
-
-  h1 {
-    font-size: 18px;
-    font-weight: 500;
-    color: $ui-base-color;
-    margin-bottom: 20px;
-  }
-
-  a {
-    color: $ui-highlight-color;
-
-    &:hover,
-    &:focus,
-    &:active {
-      color: lighten($ui-highlight-color, 4%);
-    }
-  }
-
-  p {
-    font-size: 16px;
-    color: lighten($ui-base-color, 8%);
-    margin-top: 10px;
-    margin-bottom: 10px;
-
-    &:last-child {
-      margin-bottom: 0;
-    }
-
-    strong {
-      font-weight: 500;
-      background: $ui-base-color;
-      color: $ui-secondary-color;
-      border-radius: 4px;
-      font-size: 14px;
-      padding: 3px 6px;
-
-      @each $lang in $cjk-langs {
-        &:lang(#{$lang}) {
-          font-weight: 700;
-        }
-      }
-    }
-  }
-}
-
-.onboarding-modal__page-one {
-  display: flex;
-  align-items: center;
-}
-
-.onboarding-modal__page-one__elephant-friend {
-  background: url('../images/elephant-friend-1.png') no-repeat center center / contain;
-  width: 155px;
-  height: 193px;
-  margin-right: 15px;
-}
-
-@media screen and (max-width: 400px) {
-  .onboarding-modal__page-one {
-    flex-direction: column;
-    align-items: normal;
-  }
-
-  .onboarding-modal__page-one__elephant-friend {
-    width: 100%;
-    height: 30vh;
-    max-height: 160px;
-    margin-bottom: 5vh;
-  }
-}
-
-.onboarding-modal__page-two,
-.onboarding-modal__page-three,
-.onboarding-modal__page-four,
-.onboarding-modal__page-five {
-  p {
-    text-align: left;
-  }
-
-  .figure {
-    background: darken($ui-base-color, 8%);
-    color: $ui-secondary-color;
-    margin-bottom: 20px;
-    border-radius: 4px;
-    padding: 10px;
-    text-align: center;
-    font-size: 14px;
-    box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.3);
-
-    .onboarding-modal__image {
-      border-radius: 4px;
-      margin-bottom: 10px;
-    }
-
-    &.non-interactive {
-      pointer-events: none;
-      text-align: left;
-    }
-  }
-}
-
-.onboarding-modal__page-four__columns {
-  .row {
-    display: flex;
-    margin-bottom: 20px;
-
-    & > div {
-      flex: 1 1 0;
-      margin: 0 10px;
-
-      &:first-child {
-        margin-left: 0;
-      }
-
-      &:last-child {
-        margin-right: 0;
-      }
-
-      p {
-        text-align: center;
-      }
-    }
-
-    &:last-child {
-      margin-bottom: 0;
-    }
-  }
-
-  .column-header {
-    color: $primary-text-color;
-  }
-}
-
-@media screen and (max-width: 320px) and (max-height: 600px) {
-  .onboarding-modal__page p {
-    font-size: 14px;
-    line-height: 20px;
-  }
-
-  .onboarding-modal__page-two .figure,
-  .onboarding-modal__page-three .figure,
-  .onboarding-modal__page-four .figure,
-  .onboarding-modal__page-five .figure {
-    font-size: 12px;
-    margin-bottom: 10px;
-  }
-
-  .onboarding-modal__page-four__columns .row {
-    margin-bottom: 10px;
-  }
-
-  .onboarding-modal__page-four__columns .column-header {
-    padding: 5px;
-    font-size: 12px;
-  }
-}
-
-.onboarding-modal__image {
-  border-radius: 8px;
-  width: 70vw;
-  max-width: 450px;
-  max-height: auto;
-  display: block;
-  margin: auto;
-  margin-bottom: 20px;
-}
-
-.onboard-sliders {
-  display: inline-block;
-  max-width: 30px;
-  max-height: auto;
-  margin-left: 10px;
-}
-
 .boost-modal,
 .confirmation-modal,
 .report-modal,
diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb
index a7efa73c1..4104f6cd2 100644
--- a/app/mailers/user_mailer.rb
+++ b/app/mailers/user_mailer.rb
@@ -54,4 +54,15 @@ class UserMailer < Devise::Mailer
       mail to: @resource.email, subject: I18n.t('devise.mailer.email_changed.subject')
     end
   end
+
+  def welcome(user)
+    @resource = user
+    @instance = Rails.configuration.x.local_domain
+
+    return if @resource.disabled?
+
+    I18n.with_locale(@resource.locale || I18n.default_locale) do
+      mail to: @resource.email, subject: I18n.t('user_mailer.welcome.subject')
+    end
+  end
 end
diff --git a/app/models/user.rb b/app/models/user.rb
index 892a07bba..8cad3221b 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -223,5 +223,6 @@ class User < ApplicationRecord
   def update_statistics!
     BootstrapTimelineWorker.perform_async(account_id)
     ActivityTracker.increment('activity:accounts:local')
+    UserMailer.welcome(self).deliver_later
   end
 end
diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb
index cdb284de8..87b0b2929 100644
--- a/app/views/layouts/mailer.text.erb
+++ b/app/views/layouts/mailer.text.erb
@@ -1,5 +1,5 @@
 <%= yield %>
 ---
 
-<%= t('application_mailer.signature', instance: site_hostname) %>
+<%= t 'about.hosted_on', domain: site_hostname %>
 <%= t('application_mailer.settings', link: settings_preferences_url) %>
diff --git a/app/views/user_mailer/welcome.html.haml b/app/views/user_mailer/welcome.html.haml
new file mode 100644
index 000000000..0823efa1a
--- /dev/null
+++ b/app/views/user_mailer/welcome.html.haml
@@ -0,0 +1,146 @@
+%table.email-table{ cellspacing: 0, cellpadding: 0 }
+  %tbody
+    %tr
+      %td.email-body
+        .email-container
+          %table.content-section{ cellspacing: 0, cellpadding: 0 }
+            %tbody
+              %tr
+                %td.content-cell.hero
+                  .email-row
+                    .col-6
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell.text-center.padded
+                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }
+                                %tbody
+                                  %tr
+                                    %td
+                                      = image_tag full_pack_url('icon_done.svg'), alt: ''
+
+                              %h1= t 'user_mailer.welcome.title', name: @resource.account.username
+                              %p.lead= t 'user_mailer.welcome.explanation'
+
+%table.email-table{ cellspacing: 0, cellpadding: 0 }
+  %tbody
+    %tr
+      %td.email-body
+        .email-container
+          %table.content-section{ cellspacing: 0, cellpadding: 0 }
+            %tbody
+              %tr
+                %td.content-cell
+                  .email-row
+                    .col-3
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell.input-cell.text-center.padded-bottom
+                              %h5= t 'user_mailer.welcome.full_handle'
+                              %table.input{ align: 'center', cellspacing: 0, cellpadding: 0 }
+                                %tbody
+                                  %tr
+                                    %td= "@#{@resource.account.username}@#{@instance}"
+                    .col-3
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell.content-start
+                              %p= t 'user_mailer.welcome.full_handle_hint', instance: @instance
+
+%table.email-table{ cellspacing: 0, cellpadding: 0 }
+  %tbody
+    %tr
+      %td.email-body
+        .email-container
+          %table.content-section{ cellspacing: 0, cellpadding: 0 }
+            %tbody
+              %tr
+                %td.content-cell.content-start.border-top
+                  .email-row
+                    .col-4
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell.padded
+                              = t 'user_mailer.welcome.edit_profile_step'
+                    .col-2
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell
+                              %table.button.button-small{ align: 'left', cellspacing: 0, cellpadding: 0 }
+                                %tbody
+                                  %tr
+                                    %td.button-primary
+                                      = link_to settings_profile_url do
+                                        %span= t 'user_mailer.welcome.edit_profile_action'
+              %tr
+                %td.content-cell
+                  .email-row
+                    .col-4
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell.padded
+                              = t 'user_mailer.welcome.review_preferences_step'
+                    .col-2
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell
+                              %table.button.button-small{ align: 'left', cellspacing: 0, cellpadding: 0 }
+                                %tbody
+                                  %tr
+                                    %td.button-primary
+                                      = link_to settings_preferences_url do
+                                        %span= t 'user_mailer.welcome.review_preferences_action'
+              %tr
+                %td.content-cell.padded-bottom
+                  .email-row
+                    .col-4
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell.padded
+                              = t 'user_mailer.welcome.final_step'
+                    .col-2
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell
+                              %table.button.button-small{ align: 'left', cellspacing: 0, cellpadding: 0 }
+                                %tbody
+                                  %tr
+                                    %td.button-primary
+                                      = link_to web_url do
+                                        %span= t 'user_mailer.welcome.final_action'
+
+%table.email-table{ cellspacing: 0, cellpadding: 0 }
+  %tbody
+    %tr
+      %td.email-body
+        .email-container
+          %table.content-section{ cellspacing: 0, cellpadding: 0 }
+            %tbody
+              %tr
+                %td.content-cell.border-top
+                  .email-row
+                    .col-6
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell.padded
+                              %h5= t 'user_mailer.welcome.tips'
+                              %ul
+                                %li
+                                  %span= t 'user_mailer.welcome.tip_mobile_webapp'
+                                %li
+                                  %span= t 'user_mailer.welcome.tip_bridge_html', bridge_url: 'https://bridge.joinmastodon.org'
+                                %li
+                                  %span= t 'user_mailer.welcome.tip_following'
+                                %li
+                                  %span= t 'user_mailer.welcome.tip_local_timeline', instance: @instance
+                                %li
+                                  %span= t 'user_mailer.welcome.tip_federated_timeline'
diff --git a/app/views/user_mailer/welcome.text.erb b/app/views/user_mailer/welcome.text.erb
new file mode 100644
index 000000000..5bd0cab2a
--- /dev/null
+++ b/app/views/user_mailer/welcome.text.erb
@@ -0,0 +1,30 @@
+<%= t 'user_mailer.welcome.title', name: @resource.account.username %> <%= t 'user_mailer.welcome.explanation' %>
+
+===
+
+<%= t 'user_mailer.welcome.full_handle' %> (<%= "@#{@resource.account.username}@#{@instance}" %>)
+<%= t 'user_mailer.welcome.full_handle_hint', instance: @instance %>
+
+---
+
+<%= t 'user_mailer.welcome.edit_profile_step' %>
+
+=> <%= settings_profile_url %>
+
+<%= t 'user_mailer.welcome.review_preferences_step' %>
+
+=> <%= settings_preferences_url %>
+
+<%= t 'user_mailer.welcome.final_step' %>
+
+=> <%= web_url %>
+
+---
+
+<%= t 'user_mailer.welcome.tips' %>
+
+* <%= t 'user_mailer.welcome.tip_mobile_webapp' %>
+* <%= strip_tags(t('user_mailer.welcome.tip_bridge_html')) %> (https://bridge.joinmastodon.org)
+* <%= t 'user_mailer.welcome.tip_following' %>
+* <%= t 'user_mailer.welcome.tip_local_timeline', instance: @instance %>
+* <%= t 'user_mailer.welcome.tip_federated_timeline' %>
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index 82e8e998a..eadeaef3e 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -140,7 +140,6 @@ ar:
   application_mailer:
     salutation: "%{name}،"
     settings: 'تغيير تفضيلات البريد الإلكتروني : %{link}'
-    signature: إشعارات ماستدون من %{instance}
     view: 'View:'
   applications:
     created: تم إنشاء التطبيق بنجاح
diff --git a/config/locales/bg.yml b/config/locales/bg.yml
index 13d0394a3..56a904895 100644
--- a/config/locales/bg.yml
+++ b/config/locales/bg.yml
@@ -26,7 +26,6 @@ bg:
     unfollow: Не следвай
   application_mailer:
     settings: 'Промяна на предпочитанията за e-mail: %{link}'
-    signature: Mastodon известия от %{instance}
     view: 'Преглед:'
   applications:
     invalid_url: Предоставеният URL е невалиден
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index 57e07cbd8..47b9ba995 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -340,7 +340,6 @@ ca:
   application_mailer:
     salutation: "%{name},"
     settings: 'Canvia les preferències de correu: %{link}'
-    signature: Notificacions de Mastodon des de %{instance}
     view: 'Vista:'
   applications:
     created: L'aplicació s'ha creat correctament
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 39867e373..7d0cf6349 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -321,7 +321,6 @@ de:
   application_mailer:
     salutation: "%{name},"
     settings: 'E-Mail-Einstellungen ändern: %{link}'
-    signature: Mastodon-Benachrichtigungen von %{instance}
     view: 'Ansehen:'
   applications:
     created: Anwendung erstellt
diff --git a/config/locales/en.yml b/config/locales/en.yml
index f23f35a89..cd6138ff2 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -341,7 +341,6 @@ en:
     notification_preferences: Change e-mail preferences
     salutation: "%{name},"
     settings: 'Change e-mail preferences: %{link}'
-    signature: Mastodon notifications from %{instance}
     view: 'View:'
     view_profile: View Profile
     view_status: View status
@@ -725,6 +724,25 @@ en:
     recovery_instructions_html: If you ever lose access to your phone, you can use one of the recovery codes below to regain access to your account. <strong>Keep the recovery codes safe</strong>. For example, you may print them and store them with other important documents.
     setup: Set up
     wrong_code: The entered code was invalid! Are server time and device time correct?
+  user_mailer:
+    welcome:
+      edit_profile_action: Setup profile
+      edit_profile_step: You can customize your profile by uploading an avatar, header, changing your display name and more. If you’d like to review new followers before they’re allowed to follow you, you can lock your account.
+      explanation: Here are some tips to get you started
+      final_action: Start posting
+      final_step: 'Start posting! Even without followers your public messages may be seen by others, for example on the local timeline and in hashtags. You may want to introduce yourself on the #introductions hashtag.'
+      full_handle: Your full handle
+      full_handle_hint: This is what you would tell your friends so they can message or follow you from another instance.
+      review_preferences_action: Change preferences
+      review_preferences_step: Make sure to set your preferences, such as which emails you'd like to receive, or what privacy level you’d like your posts to default to. If you don’t have motion sickness, you could choose to enable GIF autoplay.
+      subject: Welcome to Mastodon
+      tip_bridge_html: If you are coming from Twitter, you can find your friends on Mastodon by using the <a href="%{bridge_url}">bridge app</a>. It only works if they also used the bridge app though!
+      tip_federated_timeline: The federated timeline is a firehose view of the Mastodon network. But it only includes people your neighbours are subscribed to, so it's not complete.
+      tip_following: You follow your server's admin(s) by default. To find more interesting people, check the local and federated timelines.
+      tip_local_timeline: The local timeline is a firehose view of people on %{instance}. These are your immediate neighbours!
+      tip_mobile_webapp: If your mobile browser offers you to add Mastodon to your homescreen, you can receive push notifications. It acts like a native app in many ways!
+      tips: Tips
+      title: Welcome aboard, %{name}!
   users:
     invalid_email: The e-mail address is invalid
     invalid_otp_token: Invalid two-factor code
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index 847299ac7..bc259957d 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -237,7 +237,6 @@ eo:
       subject: Nova raporto por %{instance} (#%{id})
   application_mailer:
     settings: 'Ŝanĝi la retpoŝt-mesaĝajn preferojn: %{link}'
-    signature: Sciigoj de Mastodon el %{instance}
     view: 'Vidi:'
   applications:
     created: Aplikaĵo sukcesa kreis
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 18b93b08e..2b4b3c19a 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -332,7 +332,6 @@ es:
   application_mailer:
     salutation: "%{name},"
     settings: 'Cambiar preferencias de correo: %{link}'
-    signature: Notificaciones de Mastodon desde %{instance}
     view: 'Vista:'
   applications:
     created: Aplicación creada exitosamente
diff --git a/config/locales/fa.yml b/config/locales/fa.yml
index 94d4e7594..c498c592c 100644
--- a/config/locales/fa.yml
+++ b/config/locales/fa.yml
@@ -334,7 +334,6 @@ fa:
   application_mailer:
     salutation: "%{name}،"
     settings: 'تغییر تنظیمات ایمیل: %{link}'
-    signature: اعلان‌های ماستدون از %{instance}
     view: 'نمایش:'
   applications:
     created: برنامه با موفقیت ساخته شد
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index 2da8427b8..f2ee28ba0 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -25,7 +25,6 @@ fi:
     unfollow: Lopeta seuraaminen
   application_mailer:
     settings: 'Muokkaa sähköpostiasetuksia: %{link}'
-    signature: Mastodon-ilmoituksia palvelimelta %{instance}
     view: 'Katso:'
   applications:
     invalid_url: Annettu URL on väärä
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 33a307d74..c7afd5f4b 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -334,7 +334,6 @@ fr:
   application_mailer:
     salutation: "%{name},"
     settings: 'Changer les préférences courriel : %{link}'
-    signature: Notifications de Mastodon depuis %{instance}
     view: 'Voir :'
   applications:
     created: Application créée avec succès
diff --git a/config/locales/gl.yml b/config/locales/gl.yml
index 55f717249..100e2954c 100644
--- a/config/locales/gl.yml
+++ b/config/locales/gl.yml
@@ -340,7 +340,6 @@ gl:
   application_mailer:
     salutation: "%{name},"
     settings: 'Mudar as preferencias de e-mail: %{link}'
-    signature: Notificacións Mastodon de %{instance}
     view: 'Vista:'
   applications:
     created: Creouse con éxito este aplicativo
diff --git a/config/locales/he.yml b/config/locales/he.yml
index 4b977ce1b..1f27dda7a 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -229,7 +229,6 @@ he:
     title: ניהול
   application_mailer:
     settings: 'שינוי הגדרות דוא"ל: %{link}'
-    signature: התראות מסטודון מקהילת %{instance}
     view: 'תצוגה:'
   applications:
     invalid_url: כתובת הקישורית אינה חוקית
diff --git a/config/locales/hr.yml b/config/locales/hr.yml
index 581912420..a3c9aa436 100644
--- a/config/locales/hr.yml
+++ b/config/locales/hr.yml
@@ -26,7 +26,6 @@ hr:
     unfollow: Prestani slijediti
   application_mailer:
     settings: 'Promijeni e-mail postavke: %{link}'
-    signature: Mastodon notifikacije sa %{instance}
     view: 'Vidi:'
   applications:
     invalid_url: Uneseni link nije valjan
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index 77551223f..586503a35 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -12,8 +12,6 @@ hu:
     people_who_follow: "%{name} követői"
     posts: Bejegyzések
     unfollow: Követés abbahagyása
-  application_mailer:
-    signature: "%{instance} Mastodon értesítései"
   auth:
     change_password: Jelszó változtatása
     didnt_get_confirmation: Nem kaptad meg a megerősítési lépéseket?
diff --git a/config/locales/id.yml b/config/locales/id.yml
index f3a6649d1..6e4d60fd8 100644
--- a/config/locales/id.yml
+++ b/config/locales/id.yml
@@ -151,7 +151,6 @@ id:
     title: Administrasi
   application_mailer:
     settings: 'Ubah pilihan email: %{link}'
-    signature: Notifikasi Mastodon dari %{instance}
     view: 'Tampilan:'
   applications:
     invalid_url: URL tidak sesuai
diff --git a/config/locales/io.yml b/config/locales/io.yml
index 4114e5231..db8214768 100644
--- a/config/locales/io.yml
+++ b/config/locales/io.yml
@@ -149,7 +149,6 @@ io:
     title: Administration
   application_mailer:
     settings: 'Chanjar la retpost-mesajala preferi: %{link}'
-    signature: Savigi di Mastodon de %{instance}
     view: 'Vidar:'
   applications:
     invalid_url: La URL donita ne esas valida
diff --git a/config/locales/it.yml b/config/locales/it.yml
index ec0209bc1..6ab57d2fc 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -26,7 +26,6 @@ it:
     unfollow: Non seguire più
   application_mailer:
     settings: 'Cambia le impostazioni per le e-mail: %{link}'
-    signature: Notifiche Mastodon da %{instance}
     view: 'Guarda:'
   applications:
     invalid_url: L'URL fornito non è valido
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 75c133292..4ff089f6e 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -341,7 +341,6 @@ ja:
     notification_preferences: メール設定の変更
     salutation: "%{name} さん"
     settings: 'メール設定の変更: %{link}'
-    signature: Mastodon %{instance} インスタンスからの通知
     view: 'リンク:'
     view_profile: プロフィールを表示
     view_status: トゥートを表示
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index b0bac4c1d..901d6202e 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -340,7 +340,6 @@ ko:
   application_mailer:
     notification_preferences: 메일 설정 변경
     settings: '메일 설정을 변경: %{link}'
-    signature: Mastodon %{instance} 인스턴스로에서 알림
     view: 'View:'
     view_profile: 프로필 보기
     view_status: 게시물 보기
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 4c2829f98..cac9a10ec 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -340,7 +340,6 @@ nl:
   application_mailer:
     salutation: "%{name},"
     settings: 'E-mailvoorkeuren wijzigen: %{link}'
-    signature: Mastodon-meldingen van %{instance}
     view: 'Bekijk:'
   applications:
     created: Aanmaken toepassing geslaagd
diff --git a/config/locales/no.yml b/config/locales/no.yml
index 57f8547fc..3b212932e 100644
--- a/config/locales/no.yml
+++ b/config/locales/no.yml
@@ -163,7 +163,6 @@
     title: Administrasjon
   application_mailer:
     settings: 'Endre foretrukne e-postinnstillinger: %{link}'
-    signature: Mastodon-notiser fra %{instance}
     view: 'Se:'
   applications:
     invalid_url: Den oppgitte URLen er ugyldig
diff --git a/config/locales/oc.yml b/config/locales/oc.yml
index 40387de70..beb5d1f87 100644
--- a/config/locales/oc.yml
+++ b/config/locales/oc.yml
@@ -340,7 +340,6 @@ oc:
   application_mailer:
     salutation: "%{name},"
     settings: 'Cambiar las preferéncias de corrièl : %{link}'
-    signature: Notificacion de Mastodon sus %{instance}
     view: 'Veire :'
   applications:
     created: Aplicacion ben creada
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 5d77e0fda..24ae94209 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -342,7 +342,6 @@ pl:
     notification_preferences: Zmień ustawienia e-maili
     salutation: "%{name},"
     settings: 'Zmień ustawienia powiadamiania: %{link}'
-    signature: Powiadomienie Mastodona z instancji %{instance}
     view: 'Zobacz:'
     view_status: Wyświetl wpis
   applications:
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index fc4db6758..6b6fcd97c 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -340,7 +340,6 @@ pt-BR:
   application_mailer:
     salutation: "%{name},"
     settings: 'Mudar e-mail de preferência: %{link}'
-    signature: Notificações do Mastodon de %{instance}
     view: 'Visualizar:'
   applications:
     created: Aplicação criada com sucesso
diff --git a/config/locales/pt.yml b/config/locales/pt.yml
index c0056af4f..618373b91 100644
--- a/config/locales/pt.yml
+++ b/config/locales/pt.yml
@@ -328,7 +328,6 @@ pt:
   application_mailer:
     salutation: "%{name},"
     settings: 'Alterar preferências de email: %{link}'
-    signature: notificações Mastodon do %{instance}
     view: 'Ver:'
   applications:
     created: Aplicação criada com sucesso
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 6e63aadda..842fd7d54 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -342,7 +342,6 @@ ru:
     notification_preferences: Изменить настройки e-mail
     salutation: "%{name},"
     settings: 'Изменить настройки e-mail: %{link}'
-    signature: Уведомления Mastodon от %{instance}
     view: 'Просмотр:'
     view_status: Просмотреть статус
   applications:
diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml
index 964a82d64..ac80e81ec 100644
--- a/config/locales/sr-Latn.yml
+++ b/config/locales/sr-Latn.yml
@@ -336,7 +336,6 @@ sr-Latn:
   application_mailer:
     salutation: "%{name},"
     settings: 'Promeni podešavanja e-pošte: %{link}'
-    signature: Mastodont obaveštenje sa instance %{instance}
     view: 'Pogledaj:'
   applications:
     created: Aplikacija uspešno napravljena
diff --git a/config/locales/sr.yml b/config/locales/sr.yml
index 57ccf2008..755396828 100644
--- a/config/locales/sr.yml
+++ b/config/locales/sr.yml
@@ -336,7 +336,6 @@ sr:
   application_mailer:
     salutation: "%{name},"
     settings: 'Промени подешавања е-поште: %{link}'
-    signature: Мастодонт обавештење са инстанце %{instance}
     view: 'Погледај:'
   applications:
     created: Апликација успешно направљена
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index ebb6d6595..b6595cb0d 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -272,7 +272,6 @@ sv:
   application_mailer:
     salutation: "%{name},"
     settings: 'Change e-mail preferences: %{link}'
-    signature: Mastodon meddelande från %{instance}
     view: 'Granska:'
   applications:
     created: Ansökan är framgångsrikt skapad
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 2db3aee8a..737b3aa95 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -153,7 +153,6 @@ th:
     title: แอดมิน
   application_mailer:
     settings: 'เปลี่ยนอีเมล์ preferences: %{link}'
-    signature: ฟอร์มการแจ้งเตือนแมสโทดอน %{instance}
     view: 'วิว:'
   applications:
     invalid_url: URL ที่ระบุไม่ถูกตั้ง
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index 6aff78fa1..23b4d7a24 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -152,7 +152,6 @@ tr:
     title: Yönetim
   application_mailer:
     settings: 'E-mail tercihlerini değiştir: %{link}'
-    signature: "%{instance} sunucusundan Mastodon bildirimleri"
     view: 'Görüntüle:'
   applications:
     invalid_url: Verilen URL geçerli değil
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index 995a682a7..0ddfa9190 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -143,7 +143,6 @@ uk:
     title: Адміністрування
   application_mailer:
     settings: 'Змінити налаштування email: %{link}'
-    signature: Сповіщення Mastodon від %{instance}
     view: 'Перегляд:'
   applications:
     invalid_url: Введена URL неправильна
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 14382331b..25cfe5a8a 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -339,7 +339,6 @@ zh-CN:
     notification_preferences: 更改电子邮件首选项
     salutation: "%{name}:"
     settings: 使用此链接更改你的电子邮件首选项:%{link}
-    signature: 这是一封来自 %{instance} 的 Mastodon 电子邮件通知。
     view: 点此链接查看详情:
     view_profile: 查看个人资料页
     view_status: 查看嘟文
diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml
index 8ff6d1bf8..ed73b7244 100644
--- a/config/locales/zh-HK.yml
+++ b/config/locales/zh-HK.yml
@@ -152,7 +152,6 @@ zh-HK:
     title: 管理
   application_mailer:
     settings: 修改電郵設定︰%{link}
-    signature: 來自 %{instance} 的 Mastodon 通知
     view: 進入瀏覽︰
   applications:
     invalid_url: 所提供的網址不正確
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index e73dbf9cc..bd9f85840 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -123,7 +123,6 @@ zh-TW:
     title: 管理介面
   application_mailer:
     settings: 修改信箱設定︰ %{link}
-    signature: 來自 %{instance} 的 Mastodon 通知
     view: 進入瀏覽︰
   applications:
     invalid_url: 網址不正確
diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb
index 6ed0090f4..8d2a9368d 100644
--- a/spec/mailers/previews/user_mailer_preview.rb
+++ b/spec/mailers/previews/user_mailer_preview.rb
@@ -29,4 +29,9 @@ class UserMailerPreview < ActionMailer::Preview
   def reset_password_instructions
     UserMailer.reset_password_instructions(User.first, 'spec')
   end
+
+  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/welcome
+  def welcome
+    UserMailer.welcome(User.first)
+  end
 end