diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
index e573c6d04..6fe3f2267 100644
--- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
+++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
@@ -289,4 +289,9 @@ public class CacheDataSource implements DataSource {
     public List<PlayerAuth> getLoggedPlayers() {
         return new ArrayList<>(PlayerCache.getInstance().getCache().values());
     }
+
+    @Override
+    public boolean isEmailStored(String email) {
+        return source.isEmailStored(email);
+    }
 }
diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java
index 2f466defc..b59e1daa5 100644
--- a/src/main/java/fr/xephi/authme/datasource/DataSource.java
+++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java
@@ -218,6 +218,8 @@ public interface DataSource {
      */
     List<PlayerAuth> getLoggedPlayers();
 
+    boolean isEmailStored(String email);
+
     enum DataSourceType {
         MYSQL,
         FILE,
diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
index 4d7b4b38e..fd93047c0 100644
--- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java
+++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
@@ -52,13 +52,6 @@ public class FlatFile implements DataSource {
         }
     }
 
-    /**
-     * Method isAuthAvailable.
-     *
-     * @param user String
-     *
-     * @return boolean * @see fr.xephi.authme.datasource.DataSource#isAuthAvailable(String)
-     */
     @Override
     public synchronized boolean isAuthAvailable(String user) {
         BufferedReader br = null;
@@ -97,13 +90,6 @@ public class FlatFile implements DataSource {
         return null;
     }
 
-    /**
-     * Method saveAuth.
-     *
-     * @param auth PlayerAuth
-     *
-     * @return boolean * @see fr.xephi.authme.datasource.DataSource#saveAuth(PlayerAuth)
-     */
     @Override
     public synchronized boolean saveAuth(PlayerAuth auth) {
         if (isAuthAvailable(auth.getNickname())) {
@@ -127,13 +113,6 @@ public class FlatFile implements DataSource {
         return true;
     }
 
-    /**
-     * Method updatePassword.
-     *
-     * @param auth PlayerAuth
-     *
-     * @return boolean * @see fr.xephi.authme.datasource.DataSource#updatePassword(PlayerAuth)
-     */
     @Override
     public synchronized boolean updatePassword(PlayerAuth auth) {
         return updatePassword(auth.getNickname(), auth.getPassword());
@@ -200,13 +179,6 @@ public class FlatFile implements DataSource {
         return true;
     }
 
-    /**
-     * Method updateSession.
-     *
-     * @param auth PlayerAuth
-     *
-     * @return boolean * @see fr.xephi.authme.datasource.DataSource#updateSession(PlayerAuth)
-     */
     @Override
     public boolean updateSession(PlayerAuth auth) {
         if (!isAuthAvailable(auth.getNickname())) {
@@ -266,13 +238,6 @@ public class FlatFile implements DataSource {
         return true;
     }
 
-    /**
-     * Method updateQuitLoc.
-     *
-     * @param auth PlayerAuth
-     *
-     * @return boolean * @see fr.xephi.authme.datasource.DataSource#updateQuitLoc(PlayerAuth)
-     */
     @Override
     public boolean updateQuitLoc(PlayerAuth auth) {
         if (!isAuthAvailable(auth.getNickname())) {
@@ -311,13 +276,6 @@ public class FlatFile implements DataSource {
         return true;
     }
 
-    /**
-     * Method getIps.
-     *
-     * @param ip String
-     *
-     * @return int * @see fr.xephi.authme.datasource.DataSource#getIps(String)
-     */
     @Override
     public int getIps(String ip) {
         BufferedReader br = null;
@@ -348,13 +306,6 @@ public class FlatFile implements DataSource {
         }
     }
 
-    /**
-     * Method purgeDatabase.
-     *
-     * @param until long
-     *
-     * @return int * @see fr.xephi.authme.datasource.DataSource#purgeDatabase(long)
-     */
     @Override
     public int purgeDatabase(long until) {
         BufferedReader br = null;
@@ -401,13 +352,6 @@ public class FlatFile implements DataSource {
         return cleared;
     }
 
-    /**
-     * Method autoPurgeDatabase.
-     *
-     * @param until long
-     *
-     * @return List of String * @see fr.xephi.authme.datasource.DataSource#autoPurgeDatabase(long)
-     */
     @Override
     public List<String> autoPurgeDatabase(long until) {
         BufferedReader br = null;
@@ -454,13 +398,6 @@ public class FlatFile implements DataSource {
         return cleared;
     }
 
-    /**
-     * Method removeAuth.
-     *
-     * @param user String
-     *
-     * @return boolean * @see fr.xephi.authme.datasource.DataSource#removeAuth(String)
-     */
     @Override
     public synchronized boolean removeAuth(String user) {
         if (!isAuthAvailable(user)) {
@@ -505,13 +442,6 @@ public class FlatFile implements DataSource {
         return true;
     }
 
-    /**
-     * Method getAuth.
-     *
-     * @param user String
-     *
-     * @return PlayerAuth * @see fr.xephi.authme.datasource.DataSource#getAuth(String)
-     */
     @Override
     public synchronized PlayerAuth getAuth(String user) {
         BufferedReader br = null;
@@ -554,31 +484,14 @@ public class FlatFile implements DataSource {
         return null;
     }
 
-    /**
-     * Method close.
-     *
-     * @see fr.xephi.authme.datasource.DataSource#close()
-     */
     @Override
     public synchronized void close() {
     }
 
-    /**
-     * Method reload.
-     *
-     * @see fr.xephi.authme.datasource.DataSource#reload()
-     */
     @Override
     public void reload() {
     }
 
-    /**
-     * Method updateEmail.
-     *
-     * @param auth PlayerAuth
-     *
-     * @return boolean * @see fr.xephi.authme.datasource.DataSource#updateEmail(PlayerAuth)
-     */
     @Override
     public boolean updateEmail(PlayerAuth auth) {
         if (!isAuthAvailable(auth.getNickname())) {
@@ -617,13 +530,6 @@ public class FlatFile implements DataSource {
         return true;
     }
 
-    /**
-     * Method getAllAuthsByName.
-     *
-     * @param auth PlayerAuth
-     *
-     * @return List of String * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByName(PlayerAuth)
-     */
     @Override
     public List<String> getAllAuthsByName(PlayerAuth auth) {
         BufferedReader br = null;
@@ -654,13 +560,6 @@ public class FlatFile implements DataSource {
         }
     }
 
-    /**
-     * Method getAllAuthsByIp.
-     *
-     * @param ip String
-     *
-     * @return List of String * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByIp(String)
-     */
     @Override
     public List<String> getAllAuthsByIp(String ip) {
         BufferedReader br = null;
@@ -691,13 +590,6 @@ public class FlatFile implements DataSource {
         }
     }
 
-    /**
-     * Method getAllAuthsByEmail.
-     *
-     * @param email String
-     *
-     * @return List of String * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByEmail(String)
-     */
     @Override
     public List<String> getAllAuthsByEmail(String email) {
         BufferedReader br = null;
@@ -728,13 +620,6 @@ public class FlatFile implements DataSource {
         }
     }
 
-    /**
-     * Method purgeBanned.
-     *
-     * @param banned List of String
-     *
-     * @see fr.xephi.authme.datasource.DataSource#purgeBanned(List)
-     */
     @Override
     public void purgeBanned(List<String> banned) {
         BufferedReader br = null;
@@ -776,64 +661,28 @@ public class FlatFile implements DataSource {
         }
     }
 
-    /**
-     * Method getType.
-     *
-     * @return DataSourceType * @see fr.xephi.authme.datasource.DataSource#getType()
-     */
     @Override
     public DataSourceType getType() {
         return DataSourceType.FILE;
     }
 
-    /**
-     * Method isLogged.
-     *
-     * @param user String
-     *
-     * @return boolean * @see fr.xephi.authme.datasource.DataSource#isLogged(String)
-     */
     @Override
     public boolean isLogged(String user) {
         return PlayerCache.getInstance().isAuthenticated(user);
     }
 
-    /**
-     * Method setLogged.
-     *
-     * @param user String
-     *
-     * @see fr.xephi.authme.datasource.DataSource#setLogged(String)
-     */
     @Override
     public void setLogged(String user) {
     }
 
-    /**
-     * Method setUnlogged.
-     *
-     * @param user String
-     *
-     * @see fr.xephi.authme.datasource.DataSource#setUnlogged(String)
-     */
     @Override
     public void setUnlogged(String user) {
     }
 
-    /**
-     * Method purgeLogged.
-     *
-     * @see fr.xephi.authme.datasource.DataSource#purgeLogged()
-     */
     @Override
     public void purgeLogged() {
     }
 
-    /**
-     * Method getAccountsRegistered.
-     *
-     * @return int * @see fr.xephi.authme.datasource.DataSource#getAccountsRegistered()
-     */
     @Override
     public int getAccountsRegistered() {
         BufferedReader br = null;
@@ -857,14 +706,6 @@ public class FlatFile implements DataSource {
         return result;
     }
 
-    /**
-     * Method updateName.
-     *
-     * @param oldOne String
-     * @param newOne String
-     *
-     * @see fr.xephi.authme.datasource.DataSource#updateName(String, String)
-     */
     @Override
     public void updateName(String oldOne, String newOne) {
         PlayerAuth auth = this.getAuth(oldOne);
@@ -873,11 +714,6 @@ public class FlatFile implements DataSource {
         this.removeAuth(oldOne);
     }
 
-    /**
-     * Method getAllAuths.
-     *
-     * @return List of PlayerAuth * @see fr.xephi.authme.datasource.DataSource#getAllAuths()
-     */
     @Override
     public List<PlayerAuth> getAllAuths() {
         BufferedReader br = null;
@@ -925,13 +761,13 @@ public class FlatFile implements DataSource {
         return auths;
     }
 
-    /**
-     * Method getLoggedPlayers.
-     *
-     * @return List of PlayerAuth * @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers()
-     */
     @Override
     public List<PlayerAuth> getLoggedPlayers() {
         return new ArrayList<>();
     }
+
+    @Override
+    public boolean isEmailStored(String email) {
+        throw new UnsupportedOperationException("Flat file no longer supported");
+    }
 }
diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java
index 9e459ad71..21987160e 100644
--- a/src/main/java/fr/xephi/authme/datasource/MySQL.java
+++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java
@@ -971,9 +971,8 @@ public class MySQL implements DataSource {
             pst.close();
             rs.close();
             st.close();
-        } catch (Exception ex) {
-            ConsoleLogger.showError(ex.getMessage());
-            ConsoleLogger.writeStackTrace(ex);
+        } catch (SQLException ex) {
+            logSqlException(ex);
         }
         return auths;
     }
@@ -1015,11 +1014,29 @@ public class MySQL implements DataSource {
                 }
                 auths.add(pAuth);
             }
-        } catch (Exception ex) {
-            ConsoleLogger.showError(ex.getMessage());
-            ConsoleLogger.writeStackTrace(ex);
+        } catch (SQLException ex) {
+            logSqlException(ex);
         }
         return auths;
     }
 
+    @Override
+    public synchronized boolean isEmailStored(String email) {
+        String sql = "SELECT 1 FROM " + tableName + " WHERE " + columnEmail + " = ?";
+        try (Connection con = ds.getConnection()) {
+            PreparedStatement pst = con.prepareStatement(sql);
+            pst.setString(1, email);
+            ResultSet rs = pst.executeQuery();
+            return rs.next();
+        } catch (SQLException e) {
+            logSqlException(e);
+        }
+        return false;
+    }
+
+    private static void logSqlException(SQLException e) {
+        ConsoleLogger.showError("Error executing SQL query: " + StringUtils.formatException(e));
+        ConsoleLogger.writeStackTrace(e);
+    }
+
 }
diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java
index 9b14b1cc0..6ef8a406e 100644
--- a/src/main/java/fr/xephi/authme/datasource/SQLite.java
+++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java
@@ -684,6 +684,25 @@ public class SQLite implements DataSource {
         return auths;
     }
 
+    @Override
+    public synchronized boolean isEmailStored(String email) {
+        try {
+            PreparedStatement ps = con.prepareStatement(
+                "SELECT 1 FROM " + tableName + " WHERE LOWER(" + columnEmail + ") = LOWER(?)");
+            ps.setString(1, email);
+            ResultSet rs = ps.executeQuery();
+            return rs.next();
+        } catch (SQLException e) {
+            logSqlException(e);
+        }
+        return false;
+    }
+
+    private static void logSqlException(SQLException e) {
+        ConsoleLogger.showError("Error while executing SQL statement: " + StringUtils.formatException(e));
+        ConsoleLogger.writeStackTrace(e);
+    }
+
     private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException {
         String salt = !columnSalt.isEmpty() ? row.getString(columnSalt) : null;
 
diff --git a/src/main/java/fr/xephi/authme/output/MessageKey.java b/src/main/java/fr/xephi/authme/output/MessageKey.java
index fe006686a..0f33dc735 100644
--- a/src/main/java/fr/xephi/authme/output/MessageKey.java
+++ b/src/main/java/fr/xephi/authme/output/MessageKey.java
@@ -121,7 +121,9 @@ public enum MessageKey {
 
     ANTIBOT_AUTO_ENABLED_MESSAGE("antibot_auto_enabled"),
 
-    ANTIBOT_AUTO_DISABLED_MESSAGE("antibot_auto_disabled", "%m");
+    ANTIBOT_AUTO_DISABLED_MESSAGE("antibot_auto_disabled", "%m"),
+
+    EMAIL_ALREADY_USED_ERROR("email_already_used");
 
 
     private String key;
diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
index 92472ff05..a096d1507 100644
--- a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
+++ b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
@@ -36,10 +36,13 @@ public class AsyncAddEmail {
             PlayerAuth auth = playerCache.getAuth(playerName);
             String currentEmail = auth.getEmail();
 
-            if (currentEmail != null) {
+            if (currentEmail != null && !"your@mail.com".equals(currentEmail)) {
+                System.out.println("Email is currentEmail " + currentEmail); // FIXME remove
                 messages.send(player, MessageKey.USAGE_CHANGE_EMAIL);
             } else if (isEmailInvalid(email)) {
                 messages.send(player, MessageKey.INVALID_EMAIL);
+            } else if (dataSource.isEmailStored(email)) {
+                messages.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
             } else {
                 auth.setEmail(email);
                 playerCache.updatePlayer(auth);
diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java
index c69e37952..a17c262d9 100644
--- a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java
+++ b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java
@@ -44,6 +44,8 @@ public class AsyncChangeEmail {
                 m.send(player, MessageKey.INVALID_NEW_EMAIL);
             } else if (!oldEmail.equals(currentEmail)) {
                 m.send(player, MessageKey.INVALID_OLD_EMAIL);
+            } else if (dataSource.isEmailStored(newEmail)) {
+                m.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
             } else {
                 saveNewEmail(auth);
             }
diff --git a/src/main/resources/messages/messages_en.yml b/src/main/resources/messages/messages_en.yml
index 2d26cb1f6..308593861 100644
--- a/src/main/resources/messages/messages_en.yml
+++ b/src/main/resources/messages/messages_en.yml
@@ -57,3 +57,4 @@ email_exists: '&cA recovery email was already sent! You can discard it and send
 country_banned: '&4Your country is banned from this server!'
 antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!'
 antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!'
+email_already_used: '&4The email address is already being used'
diff --git a/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java b/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java
index 6d73b4710..97a6a9903 100644
--- a/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java
+++ b/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java
@@ -53,6 +53,7 @@ public class AsyncAddEmailTest {
         PlayerAuth auth = mock(PlayerAuth.class);
         given(auth.getEmail()).willReturn(null);
         given(playerCache.getAuth("tester")).willReturn(auth);
+        given(dataSource.isEmailStored("my.mail@example.org")).willReturn(false);
 
         // when
         process.process();
@@ -72,6 +73,7 @@ public class AsyncAddEmailTest {
         PlayerAuth auth = mock(PlayerAuth.class);
         given(auth.getEmail()).willReturn("another@mail.tld");
         given(playerCache.getAuth("my_player")).willReturn(auth);
+        given(dataSource.isEmailStored("some.mail@example.org")).willReturn(false);
 
         // when
         process.process();
@@ -90,6 +92,7 @@ public class AsyncAddEmailTest {
         PlayerAuth auth = mock(PlayerAuth.class);
         given(auth.getEmail()).willReturn(null);
         given(playerCache.getAuth("my_player")).willReturn(auth);
+        given(dataSource.isEmailStored("invalid_mail")).willReturn(false);
 
         // when
         process.process();
@@ -99,6 +102,25 @@ public class AsyncAddEmailTest {
         verify(playerCache, never()).updatePlayer(any(PlayerAuth.class));
     }
 
+    @Test
+    public void shouldNotAddMailIfAlreadyUsed() {
+        // given
+        AsyncAddEmail process = createProcess("player@mail.tld");
+        given(player.getName()).willReturn("TestName");
+        given(playerCache.isAuthenticated("testname")).willReturn(true);
+        PlayerAuth auth = mock(PlayerAuth.class);
+        given(auth.getEmail()).willReturn(null);
+        given(playerCache.getAuth("testname")).willReturn(auth);
+        given(dataSource.isEmailStored("player@mail.tld")).willReturn(true);
+
+        // when
+        process.process();
+
+        // then
+        verify(messages).send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
+        verify(playerCache, never()).updatePlayer(any(PlayerAuth.class));
+    }
+
     @Test
     public void shouldShowLoginMessage() {
         // given
diff --git a/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java b/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java
index 92cfec679..4faf14837 100644
--- a/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java
+++ b/src/test/java/fr/xephi/authme/process/email/AsyncChangeEmailTest.java
@@ -136,6 +136,25 @@ public class AsyncChangeEmailTest {
         verify(messages).send(player, MessageKey.INVALID_OLD_EMAIL);
     }
 
+    @Test
+    public void shouldRejectAlreadyUsedEmail() {
+        // given
+        AsyncChangeEmail process = createProcess("old@example.com", "new@example.com");
+        given(player.getName()).willReturn("Username");
+        given(playerCache.isAuthenticated("username")).willReturn(true);
+        PlayerAuth auth = authWithMail("old@example.com");
+        given(playerCache.getAuth("username")).willReturn(auth);
+        given(dataSource.isEmailStored("new@example.com")).willReturn(true);
+
+        // when
+        process.process();
+
+        // then
+        verify(dataSource, never()).updateEmail(any(PlayerAuth.class));
+        verify(playerCache, never()).updatePlayer(any(PlayerAuth.class));
+        verify(messages).send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
+    }
+
     @Test
     public void shouldSendLoginMessage() {
         // given