├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src └── Spamassassin │ ├── Client.php │ └── Client │ ├── Exception.php │ └── Result.php └── tests ├── BaseTestCase.php ├── CheckTest.php ├── ConnectionTest.php ├── HeadersTest.php ├── LearnDisabledTest.php ├── LearnEnabledTest.php ├── MaxSizeTest.php ├── ProcessTest.php ├── ReportTest.php ├── RevokeTest.php ├── SpamReportTest.php ├── SymbolsTest.php ├── ZlibCompressionTest.php └── files ├── Ham_testCheckHamMessage.txt ├── Ham_testLearnMessageAsHam.txt ├── Ham_testReportWithHamMessage.txt ├── HeadersTest_Ham.txt ├── Spam_GTUBE.txt └── Spam_testCheckSpamMessage.txt /.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /phpunit.xml 3 | /vendor/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010-2016 Pedro Padron and Templateria LTDA. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PHP SpamAssassin 2 | ===== 3 | ## Installation 4 | 5 | ### Install via Composer 6 | 7 | Add the following lines to your `composer.json` file and then run `php composer.phar install` or `php composer.phar update`: 8 | 9 | ```json 10 | { 11 | "require": { 12 | "templateria/spamassassin": "dev-master" 13 | } 14 | } 15 | ``` 16 | 17 | ## License 18 | 19 | Apache License 2.0. See [LICENSE](LICENSE) for details. 20 | 21 | ## Contributors 22 | 23 | This library is maintened by [Pedro Padron](https://github.com/ppadron) at [Templateria](https://templateria.com). 24 | 25 | A big *thank you* to all [our contributors](https://github.com/templateria/php-spamassassin/graphs/contributors): 26 | 27 | * [Alan Pinstein](https://github.com/apinstein) 28 | * [Buharin Eugene](https://github.com/webeith) 29 | * [Konstantin Pereyaslov](https://github.com/perk11) 30 | * [Christiaan Baartse](https://github.com/christiaan) 31 | * [Matt Clements](https://github.com/mattclements) 32 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "templateria/spamassassin", 3 | "description": "Spamd protocol client for PHP. PHP package that implements the spamd protocol specification", 4 | "keywords": ["spamassassin", "spamd"], 5 | "license": "Apache-2.0", 6 | "authors": [ 7 | { 8 | "name": "Pedro Padron", 9 | "email": "ppadron@php.net" 10 | } 11 | ], 12 | "require": { 13 | "php": ">=5.3.0" 14 | }, 15 | "require-dev": { 16 | "phpunit/phpunit": "~4.3.0" 17 | }, 18 | "autoload": { 19 | "classmap" : ["src/Spamassassin/"] 20 | }, 21 | "autoload-dev": { 22 | "classmap" : ["tests/"] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | 17 | 18 | tests/ 19 | 20 | 21 | 22 | 23 | 24 | SpamAssassin 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Spamassassin/Client.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://www.apache.org/licenses/LICENSE-2.0.html Apache License 2.0 12 | */ 13 | class Client 14 | { 15 | const LEARN_SPAM = 0; 16 | const LEARN_HAM = 1; 17 | const LEARN_FORGET = 2; 18 | 19 | protected $learnTypes = array( 20 | self::LEARN_SPAM, 21 | self::LEARN_HAM, 22 | self::LEARN_FORGET 23 | ); 24 | 25 | protected $hostname = 'localhost'; 26 | protected $port = '783'; 27 | 28 | protected $socketPath; 29 | protected $socket; 30 | protected $protocolVersion = '1.5'; 31 | protected $enableZlib; 32 | 33 | /** 34 | * Class constructor 35 | * 36 | * Accepts an associative array with the following keys: 37 | * 38 | * socketPath - mandatory only if using UNIX sockets to local server 39 | * hostname - mandatory only if using remote SpamAssassin server 40 | * user - optional parameter 41 | * protocolVersion - spamd protocol version (defaults to 1.5) 42 | * 43 | * @param array $params SpamAssassin parameters 44 | */ 45 | public function __construct(array $params) 46 | { 47 | foreach ($params as $param => $value) { 48 | $this->$param = $value; 49 | } 50 | } 51 | 52 | /** 53 | * Creates a new socket connection with data provided in the constructor 54 | */ 55 | protected function getSocket() 56 | { 57 | if (!empty($this->socketPath)) { 58 | $socket = fsockopen('unix://' . $this->socketPath, NULL, $errno, $errstr); 59 | } else { 60 | $socket = fsockopen($this->hostname, $this->port, $errno, $errstr); 61 | } 62 | 63 | if (!$socket) { 64 | throw new Exception( 65 | "Could not connect to SpamAssassin: {$errstr}", $errno 66 | ); 67 | } 68 | 69 | return $socket; 70 | } 71 | 72 | /** 73 | * Sends a command to the server and returns an object with the result 74 | * 75 | * @param string $cmd Protocol command to be executed 76 | * @param string $message Full email message 77 | * @param array $additionalHeaders Associative array with additional headers 78 | * 79 | * @throws Exception 80 | * 81 | * @return Result 82 | */ 83 | protected function exec($cmd, $message, array $additionalHeaders = array()) 84 | { 85 | $socket = $this->getSocket(); 86 | $message .= "\r\n"; 87 | $contentLength = strlen($message); 88 | 89 | if (!empty($this->maxSize)) { 90 | if ($contentLength > $this->maxSize) { 91 | throw new Exception( 92 | "Message exceeds the maximum allowed size of {$this->maxSize} kbytes" 93 | ); 94 | } 95 | } 96 | 97 | $cmd = $cmd . " SPAMC/" . $this->protocolVersion . "\r\n"; 98 | $cmd .= "Content-length: {$contentLength}\r\n"; 99 | 100 | if ($this->enableZlib && function_exists('gzcompress')) { 101 | $cmd .= "Compress: zlib\r\n"; 102 | $message = gzcompress($message); 103 | } 104 | 105 | if (!empty($this->user)) { 106 | $cmd .= "User: " .$this->user . "\r\n"; 107 | } 108 | 109 | if (!empty($additionalHeaders)) { 110 | foreach ($additionalHeaders as $headerName => $val) { 111 | $cmd .= $headerName . ": " . $val . "\r\n"; 112 | } 113 | } 114 | 115 | $cmd .= "\r\n"; 116 | $cmd .= $message; 117 | $cmd .= "\r\n"; 118 | 119 | $this->write($socket, $cmd); 120 | 121 | list($headers, $message) = $this->read($socket); 122 | 123 | return $this->parseOutput($headers, $message); 124 | } 125 | 126 | /** 127 | * Writes data to the socket 128 | * 129 | * @param resource $socket Socket returned by getSocket() 130 | * @param string $data Data to be written 131 | * 132 | * @return void 133 | */ 134 | protected function write($socket, $data) 135 | { 136 | fwrite($socket, $data); 137 | } 138 | 139 | /** 140 | * Reads all input from the SpamAssassin server after data was written 141 | * 142 | * @param resource $socket Socket connection created by getSocket() 143 | * 144 | * @return array Array containing output headers and message 145 | */ 146 | protected function read($socket) 147 | { 148 | $headers = ''; 149 | $message = ''; 150 | 151 | while (true) { 152 | $buffer = fgets($socket, 128); 153 | $headers .= $buffer; 154 | if ($buffer == "\r\n" || feof($socket)) { 155 | break; 156 | } 157 | } 158 | 159 | while (!feof($socket)) { 160 | $message .= fgets($socket, 128); 161 | } 162 | 163 | fclose($socket); 164 | 165 | return array(trim($headers), trim($message)); 166 | } 167 | 168 | /** 169 | * Parses SpamAssassin output ($header and $message) 170 | * 171 | * @param string $header Output headers 172 | * @param string $message Output message 173 | * 174 | * @return Result Object containing the result 175 | */ 176 | protected function parseOutput($header, $message) 177 | { 178 | $result = new Result(); 179 | 180 | /* 181 | * Matches the first line in the output. Something like this: 182 | * 183 | * SPAMD/1.5 0 EX_OK 184 | * SPAMD/1.5 68 service unavailable: TELL commands have not been enabled 185 | */ 186 | if (preg_match('/SPAMD\/(\d\.\d) (\d+) (.*)/', $header, $matches)) { 187 | $result->protocolVersion = $matches[1]; 188 | $result->responseCode = $matches[2]; 189 | $result->responseMessage = $matches[3]; 190 | 191 | if ($result->responseCode != 0) { 192 | throw new Exception( 193 | $result->responseMessage, 194 | $result->responseCode 195 | ); 196 | } 197 | 198 | } else { 199 | throw new Exception('Could not parse response header'); 200 | } 201 | 202 | if (preg_match('/Content-length: (\d+)/', $header, $matches)) { 203 | $result->contentLength = $matches[1]; 204 | } 205 | 206 | if (preg_match( 207 | '/Spam: (True|False|Yes|No) ; (\S+) \/ (\S+)/', 208 | $header, 209 | $matches 210 | )) { 211 | 212 | ($matches[1] == 'True' || $matches[1] == 'Yes') ? 213 | $result->isSpam = true : 214 | $result->isSpam = false; 215 | 216 | $result->score = (float) $matches[2]; 217 | $result->thresold = (float) $matches[3]; 218 | } else { 219 | 220 | /** 221 | * In PROCESS method with protocol version before 1.3, SpamAssassin 222 | * won't return the 'Spam:' field in the response header. In this case, 223 | * it is necessary to check for the X-Spam-Status: header in the 224 | * processed message headers. 225 | */ 226 | if (preg_match( 227 | '/X-Spam-Status: (Yes|No)\, score=(\d+\.\d) required=(\d+\.\d)/', 228 | $header.$message, 229 | $matches)) { 230 | 231 | ($matches[1] == 'Yes') ? 232 | $result->isSpam = true : 233 | $result->isSpam = false; 234 | 235 | $result->score = (float) $matches[2]; 236 | $result->thresold = (float) $matches[3]; 237 | } 238 | 239 | } 240 | 241 | /* Used for report/revoke/learn */ 242 | if (preg_match('/DidSet: (\S+)/', $header, $matches)) { 243 | $result->didSet = true; 244 | } else { 245 | $result->didSet = false; 246 | } 247 | 248 | /* Used for report/revoke/learn */ 249 | if (preg_match('/DidRemove: (\S+)/', $header, $matches)) { 250 | $result->didRemove = true; 251 | } else { 252 | $result->didRemove = false; 253 | } 254 | 255 | $result->headers = $header; 256 | $result->message = $message; 257 | 258 | return $result; 259 | 260 | } 261 | 262 | /** 263 | * Pings the server to check the connection 264 | * 265 | * @return bool 266 | */ 267 | public function ping() 268 | { 269 | $socket = $this->getSocket(); 270 | 271 | $this->write($socket, "PING SPAMC/{$this->protocolVersion}\r\n\r\n"); 272 | list($headers, $message) = $this->read($socket); 273 | 274 | if (strpos($headers, "PONG") === false) { 275 | return false; 276 | } 277 | 278 | return true; 279 | } 280 | 281 | /** 282 | * Returns a detailed report if the message is spam or null if it's ham 283 | * 284 | * @param string $message Email message 285 | * 286 | * @return Result Detailed spam report 287 | */ 288 | public function getSpamReport($message) 289 | { 290 | return $this->exec('REPORT', $message); 291 | } 292 | 293 | /** 294 | * Processes the message and returns it's headers 295 | * 296 | * This will check if the message is spam or not and return all headers 297 | * for the modified processed message. Such as X-Spam-Flag and X-Spam-Status. 298 | * 299 | * @param string $message Headers for the modified message 300 | * 301 | * @return Result Object containing the 302 | */ 303 | public function headers($message) 304 | { 305 | return $this->exec('HEADERS', $message)->message; 306 | } 307 | 308 | /** 309 | * Checks if a message is spam with the CHECK protocol command 310 | * 311 | * @param string $message Raw email message 312 | * 313 | * @return Result Object containing the result 314 | */ 315 | public function check($message) 316 | { 317 | return $this->exec('CHECK', $message); 318 | } 319 | 320 | /** 321 | * Shortcut to check() method that returns a boolean 322 | * 323 | * @param string $message Raw email message 324 | * 325 | * @return boolean Whether message is spam or not 326 | */ 327 | public function isSpam($message) 328 | { 329 | return $this->check($message)->isSpam; 330 | } 331 | 332 | /** 333 | * Shortcut to check() method that returns a float score 334 | * 335 | * @param string $message Raw email message 336 | * 337 | * @return float Spam Score of the Message 338 | */ 339 | public function getScore($message) 340 | { 341 | return $this->check($message)->score; 342 | } 343 | 344 | /** 345 | * Processes the message, checks it for spam and returning it's modified version 346 | * 347 | * @param string $message Raw email message 348 | * 349 | * @return Result Result details and modified message 350 | */ 351 | public function process($message) 352 | { 353 | return $this->exec('PROCESS', $message); 354 | } 355 | 356 | /** 357 | * Returns all rules matched by the message 358 | * 359 | * @param string $message Raw email message 360 | * 361 | * @return array Array containing the names of the rules matched 362 | */ 363 | public function symbols($message) 364 | { 365 | $result = $this->exec('SYMBOLS', $message); 366 | 367 | if (empty($result->message)) { 368 | return array(); 369 | } 370 | 371 | $symbols = explode(",", $result->message); 372 | 373 | return array_map('trim', $symbols); 374 | } 375 | 376 | /** 377 | * Uses SpamAssassin learning feature with TELL. Must be enabled on the server. 378 | * 379 | * @param string $message Raw email message 380 | * @param int $learnType self::LEARN_SPAM|self::LEARN_FORGET|self::LEARN_HAM 381 | * 382 | * @throws Exception when invalid learnType is passed 383 | * 384 | * @return bool Whether it did learn or not 385 | */ 386 | public function learn($message, $learnType = self::LEARN_SPAM) 387 | { 388 | if (!in_array($learnType, $this->learnTypes)) { 389 | throw new Exception("Invalid learn type ($learnType)"); 390 | } 391 | 392 | if ($learnType === self::LEARN_SPAM) { 393 | $additionalHeaders = array( 394 | 'Message-class' => 'spam', 395 | 'Set' => 'local', 396 | ); 397 | } elseif ($learnType === self::LEARN_HAM) { 398 | $additionalHeaders = array( 399 | 'Message-class' => 'ham', 400 | 'Set' => 'local', 401 | ); 402 | } elseif ($learnType === self::LEARN_FORGET) { 403 | $additionalHeaders = array( 404 | 'Remove' => 'local', 405 | ); 406 | } 407 | 408 | $result = $this->exec('TELL', $message, $additionalHeaders); 409 | 410 | if ($learnType === self::LEARN_SPAM || $learnType === self::LEARN_HAM) { 411 | return $result->didSet; 412 | } else { 413 | return $result->didRemove; 414 | } 415 | } 416 | 417 | /** 418 | * Report message as spam, both local and remote. 419 | * 420 | * @param string $message Raw email message 421 | * 422 | * @return bool 423 | */ 424 | public function report($message) 425 | { 426 | $additionalHeaders = array( 427 | 'Message-class' => 'spam', 428 | 'Set' => 'local,remote', 429 | ); 430 | 431 | return $this->exec('TELL', $message, $additionalHeaders)->didSet; 432 | } 433 | 434 | /** 435 | * Revokes a message previously reported as spam. 436 | * 437 | * @param string $message Raw email message 438 | * 439 | * @return bool 440 | */ 441 | public function revoke($message) 442 | { 443 | $additionalHeaders = array( 444 | 'Message-class' => 'ham', 445 | 'Set' => 'local,remote', 446 | ); 447 | 448 | return $this->exec('TELL', $message, $additionalHeaders)->didSet; 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /src/Spamassassin/Client/Exception.php: -------------------------------------------------------------------------------- 1 | 9 | * @license http://www.apache.org/licenses/LICENSE-2.0.html Apache License 2.0 10 | */ 11 | class Exception extends \Exception 12 | { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/Spamassassin/Client/Result.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://www.apache.org/licenses/LICENSE-2.0.html Apache License 2.0 12 | */ 13 | class Result 14 | { 15 | /** 16 | * The protocol version of the server response 17 | * 18 | * @var string 19 | */ 20 | public $protocolVersion; 21 | 22 | /** 23 | * Response code. 24 | * 25 | * @var int 26 | */ 27 | public $responseCode; 28 | 29 | /** 30 | * Response message. EX_OK for sucess. 31 | * 32 | * @var string 33 | */ 34 | public $responseMessage; 35 | 36 | /** 37 | * Response content length 38 | * 39 | * @var int 40 | */ 41 | public $contentLength; 42 | 43 | /** 44 | * SpamAssassin score 45 | * 46 | * @var float 47 | */ 48 | public $score; 49 | 50 | /** 51 | * How many points the message must score to be considered spam 52 | * 53 | * @var float 54 | */ 55 | public $thresold; 56 | 57 | /** 58 | * Is it spam or not? 59 | * 60 | * @var boolean 61 | */ 62 | public $isSpam; 63 | 64 | /** 65 | * Raw output from SpamAssassin server 66 | * 67 | * @var string 68 | */ 69 | public $message; 70 | 71 | /** 72 | * Output headers 73 | * 74 | * @var string 75 | */ 76 | public $headers; 77 | 78 | /** 79 | * @var bool 80 | */ 81 | public $didSet; 82 | 83 | /** 84 | * @var bool 85 | */ 86 | public $didRemove; 87 | } 88 | -------------------------------------------------------------------------------- /tests/BaseTestCase.php: -------------------------------------------------------------------------------- 1 | $GLOBALS["PHPUNIT_SA_SOCKET"], 18 | "user" => $GLOBALS["PHPUNIT_SA_USER"], 19 | ); 20 | } else { 21 | $params = array( 22 | "hostname" => $GLOBALS["PHPUNIT_SA_HOST"], 23 | "port" => (int) $GLOBALS["PHPUNIT_SA_PORT"], 24 | "user" => $GLOBALS["PHPUNIT_SA_USER"] 25 | ); 26 | } 27 | 28 | $params["protocolVersion"] = $GLOBALS["PHPUNIT_SA_PROTOCOL_VERSION"]; 29 | $this->params = $params; 30 | $this->sa = new Client($params); 31 | $this->gtube = $this->getMessage('Spam_GTUBE.txt'); 32 | $this->ham = $this->getMessage('Ham_testCheckHamMessage.txt'); 33 | } 34 | 35 | protected function getMessage($filename) 36 | { 37 | return file_get_contents(dirname(__FILE__) . '/files/' . $filename); 38 | } 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /tests/CheckTest.php: -------------------------------------------------------------------------------- 1 | getMessage('Spam_testCheckSpamMessage.txt'); 8 | $return = $this->sa->check($message); 9 | 10 | $this->assertTrue($return->isSpam); 11 | $this->assertEquals(5.0, $return->thresold); 12 | $this->assertTrue($return->score >= 1000); 13 | } 14 | 15 | public function testShouldBeAbleToCheckHamMessage() 16 | { 17 | $message = $this->getMessage('Ham_testCheckHamMessage.txt'); 18 | $return = $this->sa->check($message); 19 | 20 | $this->assertFalse($return->isSpam); 21 | } 22 | 23 | public function testIsSpamShouldBeAnAliasToCheck() 24 | { 25 | $this->assertTrue($this->sa->isSpam($this->gtube)); 26 | $this->assertFalse($this->sa->isSpam($this->ham)); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /tests/ConnectionTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(true, $this->sa->ping()); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /tests/HeadersTest.php: -------------------------------------------------------------------------------- 1 | params = array( 12 | "socketPath" => $GLOBALS["PHPUNIT_SA_SOCKET"], 13 | "user" => $GLOBALS["PHPUNIT_SA_USER"], 14 | ); 15 | } else { 16 | $this->params = array( 17 | "hostname" => $GLOBALS["PHPUNIT_SA_HOST"], 18 | "port" => (int) $GLOBALS["PHPUNIT_SA_PORT"], 19 | "user" => $GLOBALS["PHPUNIT_SA_USER"] 20 | ); 21 | } 22 | 23 | $this->gtube = $this->getMessage('Spam_GTUBE.txt'); 24 | $this->ham = $this->getMessage('Ham_testCheckHamMessage.txt'); 25 | } 26 | 27 | 28 | public function testShouldReturnProcessedSpamMessageHeaders() 29 | { 30 | $this->params["protocolVersion"] = 1.5; 31 | $sa = new Client($this->params); 32 | 33 | $message = $this->getMessage('Spam_GTUBE.txt'); 34 | $headers = $sa->headers($message); 35 | 36 | $this->assertContains("X-Spam-Status: Yes", $headers); 37 | } 38 | 39 | public function testShouldReturnProcessedHamMessageHeaders() 40 | { 41 | $this->params["protocolVersion"] = 1.5; 42 | $sa = new Client($this->params); 43 | 44 | $message = $this->getMessage('HeadersTest_Ham.txt'); 45 | $headers = $sa->headers($message); 46 | 47 | $this->assertContains("X-Spam-Status: No", $headers); 48 | } 49 | 50 | public function testShouldAlsoWorkWithProtocol13() 51 | { 52 | $this->params["protocolVersion"] = 1.3; 53 | $sa = new Client($this->params); 54 | $message = $this->getMessage('HeadersTest_Ham.txt'); 55 | $headers = $sa->headers($message); 56 | 57 | $this->assertContains("X-Spam-Status: No", $headers); 58 | } 59 | 60 | public function testShouldAlsoWorkWithProtocol12() 61 | { 62 | $this->params["protocolVersion"] = 1.2; 63 | $sa = new Client($this->params); 64 | $message = $this->getMessage('HeadersTest_Ham.txt'); 65 | $headers = $sa->headers($message); 66 | 67 | $this->assertContains("X-Spam-Status: No", $headers); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/LearnDisabledTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped( 13 | 'This test only runs when learning is disabled in SpamAssassin' 14 | ); 15 | } 16 | 17 | /* @see phpunit.xml */ 18 | if (!empty($GLOBALS["PHPUNIT_SA_SOCKET"])) { 19 | $params = array( 20 | "socketPath" => $GLOBALS["PHPUNIT_SA_SOCKET"], 21 | "user" => $GLOBALS["PHPUNIT_SA_USER"], 22 | ); 23 | } else { 24 | $params = array( 25 | "hostname" => $GLOBALS["PHPUNIT_SA_HOST"], 26 | "port" => (int) $GLOBALS["PHPUNIT_SA_PORT"], 27 | "user" => $GLOBALS["PHPUNIT_SA_USER"] 28 | ); 29 | } 30 | 31 | $params["protocolVersion"] = $GLOBALS["PHPUNIT_SA_PROTOCOL_VERSION"]; 32 | 33 | $this->sa = new Client($params); 34 | } 35 | 36 | public function testShouldThrowExceptionIfLearningIsDisabled() 37 | { 38 | $message = $this->getMessage('Spam_GTUBE.txt'); 39 | $this->setExpectedException('Spamassassin\Client\Exception'); 40 | $this->sa->learn($message, Client::LEARN_SPAM); 41 | } 42 | 43 | public function testShouldThrowExceptionWhenForgettingIfLearningIsDisabled() 44 | { 45 | $message = $this->getMessage('Spam_GTUBE.txt'); 46 | $this->setExpectedException('Spamassassin\Client\Exception'); 47 | $this->sa->learn($message, Client::LEARN_FORGET); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /tests/LearnEnabledTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped( 14 | 'To test the learning behavior, enable the TELL ' . 15 | 'command in SpamAssassin and update phpunit.xml' 16 | ); 17 | } 18 | 19 | /* @see phpunit.xml */ 20 | if (!empty($GLOBALS["PHPUNIT_SA_SOCKET"])) { 21 | $params = array( 22 | "socketPath" => $GLOBALS["PHPUNIT_SA_SOCKET"], 23 | "user" => $GLOBALS["PHPUNIT_SA_USER"], 24 | ); 25 | } else { 26 | $params = array( 27 | "hostname" => $GLOBALS["PHPUNIT_SA_HOST"], 28 | "port" => (int) $GLOBALS["PHPUNIT_SA_PORT"], 29 | "user" => $GLOBALS["PHPUNIT_SA_USER"] 30 | ); 31 | } 32 | 33 | $params["protocolVersion"] = $GLOBALS["PHPUNIT_SA_PROTOCOL_VERSION"]; 34 | 35 | $this->sa = new Client($params); 36 | 37 | } 38 | 39 | public function testShouldLearnAndMessageAsSpam() 40 | { 41 | $message = $this->getMessage('Spam_GTUBE.txt'); 42 | 43 | $this->assertTrue($this->sa->learn($message, Client::LEARN_SPAM)); 44 | $this->assertTrue($this->sa->learn($message, Client::LEARN_FORGET)); 45 | } 46 | 47 | public function testShouldLearnMessageAsHam() 48 | { 49 | $message = $this->getMessage('Ham_testLearnMessageAsHam.txt'); 50 | 51 | $this->assertTrue($this->sa->learn($message, Client::LEARN_HAM)); 52 | $this->assertTrue($this->sa->learn($message, Client::LEARN_FORGET)); 53 | } 54 | 55 | public function testShouldNotLearnIfMessageIsAlreadyKnown() 56 | { 57 | $message = $this->getMessage('Ham_testLearnMessageAsHam.txt'); 58 | 59 | /* should learn in the first call */ 60 | $this->assertTrue($this->sa->learn($message, Client::LEARN_HAM)); 61 | 62 | /* should fail in the second call because message is already known */ 63 | $this->assertFalse($this->sa->learn($message, Client::LEARN_HAM)); 64 | 65 | /* cleanup (forget message) */ 66 | $this->assertTrue($this->sa->learn($message, Client::LEARN_FORGET)); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /tests/MaxSizeTest.php: -------------------------------------------------------------------------------- 1 | setExpectedException('Spamassassin\Client\Exception'); 10 | 11 | $params = $this->params; 12 | 13 | // setting max size as 10 bytes less than message size 14 | $params['maxSize'] = strlen($this->gtube) - 10; 15 | 16 | $sa = new Client($params); 17 | 18 | $result = $sa->process($this->gtube); 19 | } 20 | 21 | public function testShouldProcessIfMessageSmallerThanMaxSize() 22 | { 23 | $result = $this->sa->process($this->gtube); 24 | $this->assertTrue($result->isSpam); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/ProcessTest.php: -------------------------------------------------------------------------------- 1 | sa->process($this->gtube); 7 | 8 | $this->assertEquals(true, $result->isSpam); 9 | $this->assertTrue(is_double($result->score)); 10 | $this->assertTrue(is_double($result->thresold)); 11 | 12 | $this->assertContains( 13 | "Content-Description: original message before SpamAssassin", 14 | $result->message 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/ReportTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped( 12 | 'To test the learning behavior, enable the TELL ' . 13 | 'command in SpamAssassin and update phpunit.xml' 14 | ); 15 | } 16 | } 17 | 18 | public function testShouldReportMessageAsSpam() 19 | { 20 | // the message cannot be older than 2 days 21 | $today = date('j, d M Y'); 22 | $message = str_replace('Thu, 29 Apr 2010', $today, $this->gtube); 23 | 24 | $this->assertTrue($this->sa->report($message)); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /tests/RevokeTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped( 12 | 'To test the learning behavior, enable the TELL ' . 13 | 'command in SpamAssassin and update phpunit.xml' 14 | ); 15 | } 16 | } 17 | 18 | public function testShouldRevokeMessageAsHam() 19 | { 20 | // the message cannot be older than 2 days 21 | $today = date('j, d M Y'); 22 | $message = str_replace('2 Jan 2010', $today, $this->ham); 23 | 24 | $this->assertTrue($this->sa->revoke($message)); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /tests/SpamReportTest.php: -------------------------------------------------------------------------------- 1 | sa->getSpamReport($this->gtube); 7 | 8 | $this->assertContains("Content preview:", $report->message); 9 | $this->assertContains("1000 GTUBE", $report->message); 10 | $this->assertTrue($report->isSpam); 11 | } 12 | 13 | public function testShouldReturnNullIfMessageIsHam() 14 | { 15 | $message = $this->getMessage('Ham_testReportWithHamMessage.txt'); 16 | $report = $this->sa->getSpamReport($message); 17 | $this->assertFalse($report->isSpam); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /tests/SymbolsTest.php: -------------------------------------------------------------------------------- 1 | sa->symbols($this->gtube); 7 | $this->assertEquals(true, in_array('GTUBE', $result)); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /tests/ZlibCompressionTest.php: -------------------------------------------------------------------------------- 1 | params; 9 | $params['enableZlib'] = true; 10 | 11 | $sa = new Client($params); 12 | $result = $sa->process($this->gtube); 13 | 14 | $this->assertTrue($result->isSpam); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/files/Ham_testCheckHamMessage.txt: -------------------------------------------------------------------------------- 1 | From announce-return-26-apmail-spamassassin-announce-archive=spamassassin.apache.org@spamassassin.apache.org Sat Jan 02 09:45:36 2010 2 | Return-Path: 3 | Delivered-To: apmail-spamassassin-announce-archive@www.apache.org 4 | Received: (qmail 27672 invoked from network); 2 Jan 2010 09:45:36 -0000 5 | Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) 6 | by minotaur.apache.org with SMTP; 2 Jan 2010 09:45:36 -0000 7 | Received: (qmail 92473 invoked by uid 500); 2 Jan 2010 09:45:31 -0000 8 | Delivered-To: apmail-spamassassin-announce-archive@spamassassin.apache.org 9 | Received: (qmail 92451 invoked by uid 500); 2 Jan 2010 09:45:31 -0000 10 | Mailing-List: contact announce-help@spamassassin.apache.org; run by ezmlm 11 | Precedence: bulk 12 | list-help: 13 | list-unsubscribe: 14 | List-Post: 15 | List-Id: 16 | Delivered-To: mailing list announce@spamassassin.apache.org 17 | Delivered-To: moderator for announce@spamassassin.apache.org 18 | Received: (qmail 52899 invoked by uid 99); 2 Jan 2010 07:42:44 -0000 19 | X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 20 | tests=ALL_TRUSTED 21 | X-Spam-Check-By: apache.org 22 | Date: 2 Jan 2010 07:42:23 -0000 23 | Message-ID: <20100102074223.6745.qmail@minotaur.apache.org> 24 | From: dos@apache.org 25 | To: dos@apache.org 26 | Subject: Apache SpamAssassin Y2K10 Rule Bug - Update Your Rules Now! 27 | 28 | I've posted the following note on the Apache SpamAssassin website [1] 29 | about an issue with a rule that may cause wanted email to be classified 30 | as spam by SpamAssassin. If you're running SpamAssassin 3.2.x you are 31 | encouraged to update you rules (updates were released on sa-update 32 | around 1900 UTC Jan 1, 2010). 33 | 34 | Y2K10 Rule Bug - Update Your Rules Now! 35 | 36 | 2010-01-01: 37 | 38 | Versions of the FH_DATE_PAST_20XX [2] rule released with versions of 39 | Apache SpamAssassin 3.2.0 thru 3.2.5 will trigger on most mail with a 40 | Date header that includes the year 2010 or later. The rule will add a 41 | score of up to 3.6 towards the spam classification of all email. You 42 | should take corrective action immediately; there are two easy ways to 43 | correct the problem: 44 | 45 | 1) If your system is configured to use sa-update [3] run sa-update now. 46 | An update is available that will correct the rule. No further action 47 | is necessary (other than restarting spamd or any service that uses 48 | SpamAssassin directly). 49 | 50 | 2) Add "score FH_DATE_PAST_20XX 0" without the quotes to the end of your 51 | local.cf file to disable the rule. If you require help updating your 52 | rules to correct this issue you are encouraged to ask for assistance on 53 | the Apache SpamAssassin Users' list. Users' mailing list info is here. [4] 54 | 55 | On behalf of the Apache SpamAssassin project I apologize for this error 56 | and the grief it may have caused you. 57 | 58 | Regards, 59 | 60 | Daryl C. W. O'Shea 61 | 62 | VP, Apache SpamAssassin 63 | 64 | [1] http://spamassassin.apache.org/ 65 | [2] http://wiki.apache.org/spamassassin/Rules/FH_DATE_PAST_20XX 66 | [3] http://wiki.apache.org/spamassassin/RuleUpdates 67 | [4] http://wiki.apache.org/spamassassin/MailingLists 68 | 69 | --------------------------------------------------------------------- 70 | To unsubscribe, e-mail: announce-unsubscribe@spamassassin.apache.org 71 | For additional commands, e-mail: announce-help@spamassassin.apache.org 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /tests/files/Ham_testLearnMessageAsHam.txt: -------------------------------------------------------------------------------- 1 | From announce-return-13-apmail-spamassassin-announce-archive=spamassassin.apache.org@spamassassin.apache.org Tue Jun 06 13:35:24 2006 2 | Return-Path: 3 | Delivered-To: apmail-spamassassin-announce-archive@www.apache.org 4 | Received: (qmail 81966 invoked from network); 6 Jun 2006 13:35:24 -0000 5 | Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) 6 | by minotaur.apache.org with SMTP; 6 Jun 2006 13:35:24 -0000 7 | Received: (qmail 55092 invoked by uid 500); 6 Jun 2006 13:35:13 -0000 8 | Delivered-To: apmail-spamassassin-announce-archive@spamassassin.apache.org 9 | Received: (qmail 55058 invoked by uid 500); 6 Jun 2006 13:35:13 -0000 10 | Mailing-List: contact announce-help@spamassassin.apache.org; run by ezmlm 11 | Precedence: bulk 12 | list-help: 13 | list-unsubscribe: 14 | List-Post: 15 | List-Id: 16 | Delivered-To: mailing list announce@spamassassin.apache.org 17 | Delivered-To: moderator for announce@spamassassin.apache.org 18 | Received: (qmail 98356 invoked by uid 99); 5 Jun 2006 16:15:38 -0000 19 | X-ASF-Spam-Status: No, hits=0.0 required=10.0 20 | tests= 21 | X-Spam-Check-By: apache.org 22 | Received-SPF: neutral (asf.osuosl.org: local policy) 23 | Date: Mon, 5 Jun 2006 12:15:14 -0400 24 | From: Theo Van Dinter 25 | To: Spamassassin Users List , 26 | Spamassassin Devel List , 27 | Spamassassin Announcements List 28 | Subject: ANNOUNCE: Apache SpamAssassin 3.0.6 available! 29 | Message-ID: <20060605161514.GO1612@kluge.net> 30 | Mime-Version: 1.0 31 | Content-Type: multipart/signed; micalg=pgp-sha1; 32 | protocol="application/pgp-signature"; boundary="mvuFargmsA+C2jC8" 33 | Content-Disposition: inline 34 | User-Agent: Mutt/1.4.2.1i 35 | X-Virus-Checked: Checked by ClamAV on apache.org 36 | X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N 37 | 38 | --mvuFargmsA+C2jC8 39 | Content-Type: text/plain; charset=us-ascii 40 | Content-Disposition: inline 41 | Content-Transfer-Encoding: quoted-printable 42 | 43 | Apache SpamAssassin 3.0.6 is now available! This is a maintainance 44 | release of the 3.0.x branch. 45 | 46 | Downloads are available from: 47 | http://spamassassin.apache.org/downloads.cgi?update=3D200606050750 48 | 49 | The release file will also be available via CPAN in the near future. 50 | 51 | md5sum of archive files: 52 | 423eb193db9f7757c6d957f5c04550cb Mail-SpamAssassin-3.0.6.tar.bz2 53 | bf0a1e1a7f6e5dd719deda6293b83e35 Mail-SpamAssassin-3.0.6.tar.gz 54 | 72c012d51f8507c2839a34f900c80412 Mail-SpamAssassin-3.0.6.zip 55 | 56 | sha1sum of archive files: 57 | 10d42d954c421f40fbbd9411a5ff096e29240c6f Mail-SpamAssassin-3.0.6.tar.bz2 58 | 78358df8ea26513a8fbe466f484d19e487e5438f Mail-SpamAssassin-3.0.6.tar.gz 59 | 17031fd2c9b54846d4e41d7ea3945639659fd91e Mail-SpamAssassin-3.0.6.zip 60 | 61 | 62 | The release files also have a .asc accompanying them. The file serves 63 | as an external GPG signature for the given release file. The signing=20 64 | key is available via the wwwkeys.pgp.net key server, as well as 65 | http://spamassassin.apache.org/released/GPG-SIGNING-KEY 66 | 67 | The key information is: 68 | 69 | pub 1024D/265FA05B 2003-06-09 SpamAssassin Signing Key 71 | Key fingerprint =3D 26C9 00A4 6DD4 0CD5 AD24 F6D7 DEE0 1987 265F A05B 72 | 73 | 3.0.6 fixes a remote code execution vulnerability if spamd is run with the 74 | "--vpopmail" and "-P" options. If either/both of those options are not 75 | used, there is no vulnerability. 76 | 77 | Changelog: 78 | 79 | - bug 4926: given a certain set of parameters to spamd and a specially 80 | formatted input message, users could cause spamd to execute arbitrary 81 | commands as the spamd user 82 | 83 | --mvuFargmsA+C2jC8 84 | Content-Type: application/pgp-signature 85 | Content-Disposition: inline 86 | 87 | -----BEGIN PGP SIGNATURE----- 88 | Version: GnuPG v1.4.2.2 (GNU/Linux) 89 | 90 | iD8DBQFEhFiSvTLro+k8grsRAoI9AJ9SjVCxDIJ6z9SlmmZwLn1RaWYaugCfWoZJ 91 | U0bB5y5qX5kj4BbwLFQfIt8= 92 | =An3l 93 | -----END PGP SIGNATURE----- 94 | 95 | --mvuFargmsA+C2jC8-- 96 | -------------------------------------------------------------------------------- /tests/files/Ham_testReportWithHamMessage.txt: -------------------------------------------------------------------------------- 1 | From announce-return-26-apmail-spamassassin-announce-archive=spamassassin.apache.org@spamassassin.apache.org Sat Jan 02 09:45:36 2010 2 | Return-Path: 3 | Delivered-To: apmail-spamassassin-announce-archive@www.apache.org 4 | Received: (qmail 27672 invoked from network); 2 Jan 2010 09:45:36 -0000 5 | Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) 6 | by minotaur.apache.org with SMTP; 2 Jan 2010 09:45:36 -0000 7 | Received: (qmail 92473 invoked by uid 500); 2 Jan 2010 09:45:31 -0000 8 | Delivered-To: apmail-spamassassin-announce-archive@spamassassin.apache.org 9 | Received: (qmail 92451 invoked by uid 500); 2 Jan 2010 09:45:31 -0000 10 | Mailing-List: contact announce-help@spamassassin.apache.org; run by ezmlm 11 | Precedence: bulk 12 | list-help: 13 | list-unsubscribe: 14 | List-Post: 15 | List-Id: 16 | Delivered-To: mailing list announce@spamassassin.apache.org 17 | Delivered-To: moderator for announce@spamassassin.apache.org 18 | Received: (qmail 52899 invoked by uid 99); 2 Jan 2010 07:42:44 -0000 19 | X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 20 | tests=ALL_TRUSTED 21 | X-Spam-Check-By: apache.org 22 | Date: 2 Jan 2010 07:42:23 -0000 23 | Message-ID: <20100102074223.6745.qmail@minotaur.apache.org> 24 | From: dos@apache.org 25 | To: dos@apache.org 26 | Subject: Apache SpamAssassin Y2K10 Rule Bug - Update Your Rules Now! 27 | 28 | I've posted the following note on the Apache SpamAssassin website [1] 29 | about an issue with a rule that may cause wanted email to be classified 30 | as spam by SpamAssassin. If you're running SpamAssassin 3.2.x you are 31 | encouraged to update you rules (updates were released on sa-update 32 | around 1900 UTC Jan 1, 2010). 33 | 34 | Y2K10 Rule Bug - Update Your Rules Now! 35 | 36 | 2010-01-01: 37 | 38 | Versions of the FH_DATE_PAST_20XX [2] rule released with versions of 39 | Apache SpamAssassin 3.2.0 thru 3.2.5 will trigger on most mail with a 40 | Date header that includes the year 2010 or later. The rule will add a 41 | score of up to 3.6 towards the spam classification of all email. You 42 | should take corrective action immediately; there are two easy ways to 43 | correct the problem: 44 | 45 | 1) If your system is configured to use sa-update [3] run sa-update now. 46 | An update is available that will correct the rule. No further action 47 | is necessary (other than restarting spamd or any service that uses 48 | SpamAssassin directly). 49 | 50 | 2) Add "score FH_DATE_PAST_20XX 0" without the quotes to the end of your 51 | local.cf file to disable the rule. If you require help updating your 52 | rules to correct this issue you are encouraged to ask for assistance on 53 | the Apache SpamAssassin Users' list. Users' mailing list info is here. [4] 54 | 55 | On behalf of the Apache SpamAssassin project I apologize for this error 56 | and the grief it may have caused you. 57 | 58 | Regards, 59 | 60 | Daryl C. W. O'Shea 61 | 62 | VP, Apache SpamAssassin 63 | 64 | [1] http://spamassassin.apache.org/ 65 | [2] http://wiki.apache.org/spamassassin/Rules/FH_DATE_PAST_20XX 66 | [3] http://wiki.apache.org/spamassassin/RuleUpdates 67 | [4] http://wiki.apache.org/spamassassin/MailingLists 68 | 69 | --------------------------------------------------------------------- 70 | To unsubscribe, e-mail: announce-unsubscribe@spamassassin.apache.org 71 | For additional commands, e-mail: announce-help@spamassassin.apache.org 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /tests/files/HeadersTest_Ham.txt: -------------------------------------------------------------------------------- 1 | From announce-return-9-apmail-spamassassin-announce-archive=spamassassin.apache.org@spamassassin.apache.org Wed Jun 15 20:12:57 2005 2 | Return-Path: 3 | Delivered-To: apmail-spamassassin-announce-archive@www.apache.org 4 | Received: (qmail 560 invoked from network); 15 Jun 2005 20:11:48 -0000 5 | Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) 6 | by minotaur.apache.org with SMTP; 15 Jun 2005 20:11:48 -0000 7 | Received: (qmail 48551 invoked by uid 500); 15 Jun 2005 20:11:37 -0000 8 | Delivered-To: apmail-spamassassin-announce-archive@spamassassin.apache.org 9 | Received: (qmail 48455 invoked by uid 500); 15 Jun 2005 20:11:36 -0000 10 | Mailing-List: contact announce-help@spamassassin.apache.org; run by ezmlm 11 | Precedence: bulk 12 | list-help: 13 | list-unsubscribe: 14 | List-Post: 15 | List-Id: 16 | Delivered-To: mailing list announce@spamassassin.apache.org 17 | Delivered-To: moderator for announce@spamassassin.apache.org 18 | Received: (qmail 18095 invoked by uid 99); 15 Jun 2005 20:00:59 -0000 19 | X-ASF-Spam-Status: No, hits=-0.0 required=10.0 20 | tests=SPF_HELO_PASS,SPF_PASS 21 | X-Spam-Check-By: apache.org 22 | Received-SPF: pass (hermes.apache.org: domain of quinlan@pathname.com designates 209.204.178.122 as permitted sender) 23 | From: Daniel Quinlan 24 | MIME-Version: 1.0 25 | Content-Type: text/plain; charset=us-ascii 26 | Content-Transfer-Encoding: 7bit 27 | Message-ID: <17072.35054.586017.822288@proton.pathname.com> 28 | Date: Wed, 15 Jun 2005 13:00:46 -0700 29 | To: announce@spamassassin.apache.org 30 | Cc: users@spamassassin.apache.org, dev@spamassassin.apache.org 31 | Subject: Denial of Service Vulnerability in Apache SpamAssassin 3.0.1-3.0.3 32 | X-Mailer: VM 7.16 under Emacs 20.7.2 33 | Reply-To: users@spamassassin.apache.org 34 | X-Virus-Checked: Checked 35 | X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N 36 | 37 | Apache SpamAssassin 3.0.4 was recently released [0], and fixes a denial 38 | of service vulnerability in versions 3.0.1, 3.0.2, and 3.0.3. The 39 | vulnerability allows certain misformatted long message headers to cause 40 | spam checking to take a very long time. 41 | 42 | While the exploit has yet to be seen in the wild, we are concerned that 43 | there may be attempts to abuse the vulnerability in the future. 44 | Therefore, we strongly recommend all users of these versions upgrade to 45 | Apache SpamAssassin 3.0.4 as soon as possible. 46 | 47 | This issue has been assigned CVE id CAN-2005-1266 [1]. 48 | 49 | To contact the Apache SpamAssassin security team, please e-mail 50 | security at spamassassin.apache.org. For more information about Apache 51 | SpamAssassin, visit the http://spamassassin.apache.org/ web site. 52 | 53 | Apache SpamAssassin Security Team 54 | 55 | [0]: http://mail-archives.apache.org/mod_mbox/spamassassin-dev/200506.mbox/%3c20050606223631.GG11538@kluge.net%3e 56 | 57 | [1]: http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-1266 58 | 59 | --------------------------------------------------------------------- 60 | To unsubscribe, e-mail: announce-unsubscribe@spamassassin.apache.org 61 | For additional commands, e-mail: announce-help@spamassassin.apache.org 62 | 63 | 64 | -------------------------------------------------------------------------------- /tests/files/Spam_GTUBE.txt: -------------------------------------------------------------------------------- 1 | Subject: Test spam mail (GTUBE) 2 | Message-ID: 3 | Date: Thu, 29 Apr 2010 23:30:00 +0200 4 | From: Sender 5 | To: Recipient 6 | Precedence: junk 7 | MIME-Version: 1.0 8 | Content-Type: text/plain; charset=us-ascii 9 | Content-Transfer-Encoding: 7bit 10 | 11 | This is the GTUBE, the 12 | Generic 13 | Test for 14 | Unsolicited 15 | Bulk 16 | Email 17 | 18 | If your spam filter supports it, the GTUBE provides a test by which you 19 | can verify that the filter is installed correctly and is detecting incoming 20 | spam. You can send yourself a test mail containing the following string of 21 | characters (in upper case and with no white spaces and line breaks): 22 | 23 | XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X 24 | 25 | You should send this test mail from an account outside of your network. 26 | 27 | -------------------------------------------------------------------------------- /tests/files/Spam_testCheckSpamMessage.txt: -------------------------------------------------------------------------------- 1 | Subject: Test spam mail (GTUBE) 2 | Message-ID: 3 | Date: Wed, 23 Jul 2003 23:30:00 +0200 4 | From: Sender 5 | To: Recipient 6 | Precedence: junk 7 | MIME-Version: 1.0 8 | Content-Type: text/plain; charset=us-ascii 9 | Content-Transfer-Encoding: 7bit 10 | 11 | This is the GTUBE, the 12 | Generic 13 | Test for 14 | Unsolicited 15 | Bulk 16 | Email 17 | 18 | If your spam filter supports it, the GTUBE provides a test by which you 19 | can verify that the filter is installed correctly and is detecting incoming 20 | spam. You can send yourself a test mail containing the following string of 21 | characters (in upper case and with no white spaces and line breaks): 22 | 23 | XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X 24 | 25 | You should send this test mail from an account outside of your network. 26 | 27 | --------------------------------------------------------------------------------